diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index a073dd5670..cf7d0e1f10 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -14,57 +14,62 @@ }, { "ImportPath": "github.com/coreos/etcd/client", - "Comment": "v2.3.0-alpha.0-390-gc70d533", - "Rev": "c70d53377134659390f79c00b47e4f2bdd1d01d6" + "Comment": "v2.3.0-alpha.0-430-g374b14e", + "Rev": "374b14e47189c249c069c9b3376cf5c36f286fa6" }, { "ImportPath": "github.com/coreos/etcd/pkg/pathutil", - "Comment": "v2.3.0-alpha.0-390-gc70d533", - "Rev": "c70d53377134659390f79c00b47e4f2bdd1d01d6" + "Comment": "v2.3.0-alpha.0-430-g374b14e", + "Rev": "374b14e47189c249c069c9b3376cf5c36f286fa6" }, { "ImportPath": "github.com/coreos/etcd/pkg/types", - "Comment": "v2.3.0-alpha.0-390-gc70d533", - "Rev": "c70d53377134659390f79c00b47e4f2bdd1d01d6" + "Comment": "v2.3.0-alpha.0-430-g374b14e", + "Rev": "374b14e47189c249c069c9b3376cf5c36f286fa6" }, { "ImportPath": "github.com/davecgh/go-spew/spew", "Rev": "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d" }, { - "ImportPath": "github.com/docker/docker/api/types/filters", - "Comment": "v1.4.1-8996-g7fab931", - "Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e" + "ImportPath": "github.com/docker/docker/pkg/discovery", + "Comment": "v1.4.1-9107-gf11b6a2", + "Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6" }, { "ImportPath": "github.com/docker/docker/pkg/ioutils", - "Comment": "v1.4.1-8996-g7fab931", - "Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e" + "Comment": "v1.4.1-9107-gf11b6a2", + "Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6" }, { "ImportPath": "github.com/docker/docker/pkg/longpath", - "Comment": "v1.4.1-8996-g7fab931", - "Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e" + "Comment": "v1.4.1-9107-gf11b6a2", + "Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6" }, { "ImportPath": "github.com/docker/docker/pkg/random", - "Comment": "v1.4.1-8996-g7fab931", - "Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e" + "Comment": "v1.4.1-9107-gf11b6a2", + "Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6" }, { "ImportPath": "github.com/docker/docker/pkg/stringid", - "Comment": "v1.4.1-8996-g7fab931", - "Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e" - }, - { - "ImportPath": "github.com/docker/docker/pkg/tlsconfig", - "Comment": "v1.4.1-8996-g7fab931", - "Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e" + "Comment": "v1.4.1-9107-gf11b6a2", + "Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6" }, { "ImportPath": "github.com/docker/docker/pkg/version", - "Comment": "v1.4.1-8996-g7fab931", - "Rev": "7fab93175d605f98cddf811819d9ab081bb4f90e" + "Comment": "v1.4.1-9107-gf11b6a2", + "Rev": "f11b6a2ab313a03d051dd6f69d264d0482df72d6" + }, + { + "ImportPath": "github.com/docker/engine-api/types/filters", + "Comment": "v0.2.0", + "Rev": "259fce04b5a17bc7a202090d52ca873762fa8b25" + }, + { + "ImportPath": "github.com/docker/go-connections/tlsconfig", + "Comment": "v0.1.2", + "Rev": "4e42727957c146776e5de9cec8c39e4059ed9f20" }, { "ImportPath": "github.com/docker/go-units", @@ -95,8 +100,8 @@ }, { "ImportPath": "github.com/hashicorp/consul/api", - "Comment": "v0.6.0-121-g68969ce", - "Rev": "68969ce5f4499cbe3a4f946917be2e580f1b1936" + "Comment": "v0.6.1-11-g562bf11", + "Rev": "562bf11e9ff784824f9c5fec0ad3609805e13a3d" }, { "ImportPath": "github.com/hashicorp/go-cleanhttp", @@ -148,7 +153,7 @@ }, { "ImportPath": "github.com/pmezard/go-difflib/difflib", - "Rev": "e8554b8641db39598be7f6342874b958f12ae1d4" + "Rev": "792786c7400a136282c1664665ae0a8db921c6c2" }, { "ImportPath": "github.com/samalba/dockerclient", @@ -168,13 +173,13 @@ }, { "ImportPath": "github.com/stretchr/testify/assert", - "Comment": "v1.0-91-g5b9da39", - "Rev": "5b9da39b66e8e994455c2525c4421c8cc00a7f93" + "Comment": "v1.1.3", + "Rev": "f390dcf405f7b83c997eac1b06768bb9f44dec18" }, { "ImportPath": "github.com/stretchr/testify/mock", - "Comment": "v1.0-91-g5b9da39", - "Rev": "5b9da39b66e8e994455c2525c4421c8cc00a7f93" + "Comment": "v1.1.3", + "Rev": "f390dcf405f7b83c997eac1b06768bb9f44dec18" }, { "ImportPath": "github.com/ugorji/go/codec", @@ -182,7 +187,7 @@ }, { "ImportPath": "golang.org/x/net/context", - "Rev": "1ade16a5450925b7496e1031938175d1f5d30d31" + "Rev": "4fd4a9fed55e5bdee4a89d6406c2eabe38b60300" }, { "ImportPath": "golang.org/x/sys/unix", diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/README.md b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/README.md new file mode 100644 index 0000000000..39777c2171 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/README.md @@ -0,0 +1,41 @@ +--- +page_title: Docker discovery +page_description: discovery +page_keywords: docker, clustering, discovery +--- + +# Discovery + +Docker comes with multiple Discovery backends. + +## Backends + +### Using etcd + +Point your Docker Engine instances to a common etcd instance. You can specify +the address Docker uses to advertise the node using the `--cluster-advertise` +flag. + +```bash +$ docker daemon -H= --cluster-advertise= --cluster-store etcd://,/ +``` + +### Using consul + +Point your Docker Engine instances to a common Consul instance. You can specify +the address Docker uses to advertise the node using the `--cluster-advertise` +flag. + +```bash +$ docker daemon -H= --cluster-advertise= --cluster-store consul:/// +``` + +### Using zookeeper + +Point your Docker Engine instances to a common Zookeeper instance. You can specify +the address Docker uses to advertise the node using the `--cluster-advertise` +flag. + +```bash +$ docker daemon -H= --cluster-advertise= --cluster-store zk://,/ +``` diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/backends.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/backends.go new file mode 100644 index 0000000000..875a26c442 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/backends.go @@ -0,0 +1,111 @@ +package discovery + +import ( + "fmt" + "net" + "strings" + "time" + + log "github.com/Sirupsen/logrus" +) + +var ( + // Backends is a global map of discovery backends indexed by their + // associated scheme. + backends map[string]Backend +) + +func init() { + backends = make(map[string]Backend) +} + +// 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 Backend) error { + if _, exists := backends[scheme]; exists { + return fmt.Errorf("scheme already registered %s", scheme) + } + log.WithField("name", scheme).Debug("Registering discovery service") + backends[scheme] = d + return nil +} + +func parse(rawurl string) (string, string) { + parts := strings.SplitN(rawurl, "://", 2) + + // nodes:port,node2:port => nodes://node1:port,node2:port + if len(parts) == 1 { + return "nodes", parts[0] + } + return parts[0], parts[1] +} + +// ParseAdvertise parses the --cluster-advertise daemon config which accepts +// : or : +func ParseAdvertise(store, advertise string) (string, error) { + var ( + iface *net.Interface + addrs []net.Addr + err error + ) + + addr, port, err := net.SplitHostPort(advertise) + + if err != nil { + return "", fmt.Errorf("invalid --cluster-advertise configuration: %s: %v", advertise, err) + } + + ip := net.ParseIP(addr) + // If it is a valid ip-address, use it as is + if ip != nil { + return advertise, nil + } + + // If advertise is a valid interface name, get the valid ipv4 address and use it to advertise + ifaceName := addr + iface, err = net.InterfaceByName(ifaceName) + if err != nil { + return "", fmt.Errorf("invalid cluster advertise IP address or interface name (%s) : %v", advertise, err) + } + + addrs, err = iface.Addrs() + if err != nil { + return "", fmt.Errorf("unable to get advertise IP address from interface (%s) : %v", advertise, err) + } + + if addrs == nil || len(addrs) == 0 { + return "", fmt.Errorf("no available advertise IP address in interface (%s)", advertise) + } + + addr = "" + for _, a := range addrs { + ip, _, err := net.ParseCIDR(a.String()) + if err != nil { + return "", fmt.Errorf("error deriving advertise ip-address in interface (%s) : %v", advertise, err) + } + if ip.To4() == nil || ip.IsLoopback() { + continue + } + addr = ip.String() + break + } + if addr == "" { + return "", fmt.Errorf("couldnt find a valid ip-address in interface %s", advertise) + } + + addr = fmt.Sprintf("%s:%s", addr, port) + return addr, nil +} + +// 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, clusterOpts map[string]string) (Backend, error) { + scheme, uri := parse(rawurl) + if backend, exists := backends[scheme]; exists { + log.WithFields(log.Fields{"name": scheme, "uri": uri}).Debug("Initializing discovery service") + err := backend.Initialize(uri, heartbeat, ttl, clusterOpts) + return backend, err + } + + return nil, ErrNotSupported +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/discovery.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/discovery.go new file mode 100644 index 0000000000..ca7f587458 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/discovery.go @@ -0,0 +1,35 @@ +package discovery + +import ( + "errors" + "time" +) + +var ( + // ErrNotSupported is returned when a discovery service is not supported. + ErrNotSupported = errors.New("discovery service not supported") + + // ErrNotImplemented is returned when discovery feature is not implemented + // by discovery backend. + ErrNotImplemented = errors.New("not implemented in this discovery service") +) + +// Watcher provides watching over a cluster for nodes joining and leaving. +type Watcher interface { + // 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) +} + +// Backend is implemented by discovery backends which manage cluster entries. +type Backend interface { + // Watcher must be provided by every backend. + Watcher + + // Initialize the discovery with URIs, a heartbeat, a ttl and optional settings. + Initialize(string, time.Duration, time.Duration, map[string]string) error + + // Register to the discovery. + Register(string) error +} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/entry.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/entry.go new file mode 100644 index 0000000000..e9cee26ee1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/entry.go @@ -0,0 +1,97 @@ +package discovery + +import ( + "fmt" + "net" +) + +// NewEntry creates a new entry. +func NewEntry(url string) (*Entry, error) { + host, port, err := net.SplitHostPort(url) + if err != nil { + return nil, err + } + return &Entry{host, port}, nil +} + +// An Entry represents a host. +type Entry struct { + Host string + Port string +} + +// 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 +} + +// String returns the string form of an entry. +func (e *Entry) String() string { + return fmt.Sprintf("%s:%s", e.Host, e.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 +} + +// 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 +} + +// CreateEntries returns an array of entries based on the given addresses. +func CreateEntries(addrs []string) (Entries, error) { + entries := Entries{} + if addrs == nil { + return entries, nil + } + + for _, addr := range addrs { + if len(addr) == 0 { + continue + } + entry, err := NewEntry(addr) + if err != nil { + return nil, err + } + entries = append(entries, entry) + } + return entries, nil +} diff --git a/discovery/file/file.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/file/file.go similarity index 98% rename from discovery/file/file.go rename to Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/file/file.go index 1ec72ad398..b4f870b864 100644 --- a/discovery/file/file.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/file/file.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/docker/swarm/discovery" + "github.com/docker/docker/pkg/discovery" ) // Discovery is exported diff --git a/discovery/generator.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/generator.go similarity index 100% rename from discovery/generator.go rename to Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/generator.go diff --git a/discovery/kv/kv.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/kv/kv.go similarity index 84% rename from discovery/kv/kv.go rename to Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/kv/kv.go index fb578e9957..f371c0cba0 100644 --- a/discovery/kv/kv.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/kv/kv.go @@ -7,17 +7,17 @@ import ( "time" log "github.com/Sirupsen/logrus" - "github.com/docker/docker/pkg/tlsconfig" + "github.com/docker/docker/pkg/discovery" + "github.com/docker/go-connections/tlsconfig" "github.com/docker/libkv" "github.com/docker/libkv/store" "github.com/docker/libkv/store/consul" "github.com/docker/libkv/store/etcd" "github.com/docker/libkv/store/zookeeper" - "github.com/docker/swarm/discovery" ) const ( - defaultDiscoveryPath = "docker/swarm/nodes" + defaultDiscoveryPath = "docker/nodes" ) // Discovery is exported @@ -41,14 +41,14 @@ func Init() { consul.Register() etcd.Register() - // Register to internal Swarm discovery service + // Register to internal discovery service discovery.Register("zk", &Discovery{backend: store.ZK}) discovery.Register("consul", &Discovery{backend: store.CONSUL}) discovery.Register("etcd", &Discovery{backend: store.ETCD}) } // Initialize is exported -func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Duration, discoveryOpt map[string]string) error { +func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Duration, clusterOpts map[string]string) error { var ( parts = strings.SplitN(uris, "/", 2) addrs = strings.Split(parts[0], ",") @@ -65,19 +65,19 @@ func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Du // Use a custom path if specified in discovery options dpath := defaultDiscoveryPath - if discoveryOpt["kv.path"] != "" { - dpath = discoveryOpt["kv.path"] + if clusterOpts["kv.path"] != "" { + dpath = clusterOpts["kv.path"] } s.path = path.Join(s.prefix, dpath) var config *store.Config - if discoveryOpt["kv.cacertfile"] != "" && discoveryOpt["kv.certfile"] != "" && discoveryOpt["kv.keyfile"] != "" { - log.Debug("Initializing discovery with TLS") + if clusterOpts["kv.cacertfile"] != "" && clusterOpts["kv.certfile"] != "" && clusterOpts["kv.keyfile"] != "" { + log.Info("Initializing discovery with TLS") tlsConfig, err := tlsconfig.Client(tlsconfig.Options{ - CAFile: discoveryOpt["kv.cacertfile"], - CertFile: discoveryOpt["kv.certfile"], - KeyFile: discoveryOpt["kv.keyfile"], + CAFile: clusterOpts["kv.cacertfile"], + CertFile: clusterOpts["kv.certfile"], + KeyFile: clusterOpts["kv.keyfile"], }) if err != nil { return err @@ -85,15 +85,15 @@ func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Du config = &store.Config{ // Set ClientTLS to trigger https (bug in libkv/etcd) ClientTLS: &store.ClientTLSConfig{ - CACertFile: discoveryOpt["kv.cacertfile"], - CertFile: discoveryOpt["kv.certfile"], - KeyFile: discoveryOpt["kv.keyfile"], + CACertFile: clusterOpts["kv.cacertfile"], + CertFile: clusterOpts["kv.certfile"], + KeyFile: clusterOpts["kv.keyfile"], }, // The actual TLS config that will be used TLS: tlsConfig, } } else { - log.Debug("Initializing discovery without TLS") + log.Info("Initializing discovery without TLS") } // Creates a new store, will ignore options given @@ -172,7 +172,6 @@ func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-c time.Sleep(s.heartbeat) } }() - return ch, errCh } diff --git a/discovery/nodes/nodes.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/nodes/nodes.go similarity index 96% rename from discovery/nodes/nodes.go rename to Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/nodes/nodes.go index 181a15879f..c0e3c07b22 100644 --- a/discovery/nodes/nodes.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/discovery/nodes/nodes.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "github.com/docker/swarm/discovery" + "github.com/docker/docker/pkg/discovery" ) // Discovery is exported diff --git a/Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/docker/engine-api/LICENSE b/Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/docker/engine-api/LICENSE new file mode 100644 index 0000000000..c157bff96a --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/docker/engine-api/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015-2016 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/miekg/dns/COPYRIGHT b/Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/miekg/dns/COPYRIGHT new file mode 100644 index 0000000000..35702b10e8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/miekg/dns/COPYRIGHT @@ -0,0 +1,9 @@ +Copyright 2009 The Go Authors. All rights reserved. Use of this source code +is governed by a BSD-style license that can be found in the LICENSE file. +Extensions of the original work are copyright (c) 2011 Miek Gieben + +Copyright 2011 Miek Gieben. All rights reserved. Use of this source code is +governed by a BSD-style license that can be found in the LICENSE file. + +Copyright 2014 CloudFlare. All rights reserved. Use of this source code is +governed by a BSD-style license that can be found in the LICENSE file. diff --git a/Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/miekg/dns/LICENSE b/Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/miekg/dns/LICENSE new file mode 100644 index 0000000000..5763fa7fe5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/vendor/src/github.com/miekg/dns/LICENSE @@ -0,0 +1,32 @@ +Extensions of the original work are copyright (c) 2011 Miek Gieben + +As this is fork of the official Go code the same license applies: + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/Godeps/_workspace/src/github.com/docker/engine-api/LICENSE b/Godeps/_workspace/src/github.com/docker/engine-api/LICENSE new file mode 100644 index 0000000000..c157bff96a --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/engine-api/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015-2016 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Godeps/_workspace/src/github.com/docker/docker/api/types/filters/parse.go b/Godeps/_workspace/src/github.com/docker/engine-api/types/filters/parse.go similarity index 100% rename from Godeps/_workspace/src/github.com/docker/docker/api/types/filters/parse.go rename to Godeps/_workspace/src/github.com/docker/engine-api/types/filters/parse.go diff --git a/Godeps/_workspace/src/github.com/docker/go-connections/LICENSE b/Godeps/_workspace/src/github.com/docker/go-connections/LICENSE new file mode 100644 index 0000000000..b55b37bc31 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/go-connections/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/tlsconfig/config.go b/Godeps/_workspace/src/github.com/docker/go-connections/tlsconfig/config.go similarity index 100% rename from Godeps/_workspace/src/github.com/docker/docker/pkg/tlsconfig/config.go rename to Godeps/_workspace/src/github.com/docker/go-connections/tlsconfig/config.go diff --git a/Godeps/_workspace/src/github.com/pmezard/go-difflib/difflib/difflib.go b/Godeps/_workspace/src/github.com/pmezard/go-difflib/difflib/difflib.go index e5005daaa3..003e99fadb 100644 --- a/Godeps/_workspace/src/github.com/pmezard/go-difflib/difflib/difflib.go +++ b/Godeps/_workspace/src/github.com/pmezard/go-difflib/difflib/difflib.go @@ -585,13 +585,15 @@ func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error { if len(diff.ToDate) > 0 { toDate = "\t" + diff.ToDate } - err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol) - if err != nil { - return err - } - err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol) - if err != nil { - return err + if diff.FromFile != "" || diff.ToFile != "" { + err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol) + if err != nil { + return err + } + err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol) + if err != nil { + return err + } } } first, last := g[0], g[len(g)-1] @@ -710,8 +712,10 @@ func WriteContextDiff(writer io.Writer, diff ContextDiff) error { if len(diff.ToDate) > 0 { toDate = "\t" + diff.ToDate } - wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol) - wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol) + if diff.FromFile != "" || diff.ToFile != "" { + wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol) + wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol) + } } first, last := g[0], g[len(g)-1] diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertion_forward.go b/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertion_forward.go new file mode 100644 index 0000000000..e6a796046c --- /dev/null +++ b/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertion_forward.go @@ -0,0 +1,387 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND +*/ + +package assert + +import ( + + http "net/http" + url "net/url" + time "time" +) + + +// Condition uses a Comparison to assert a complex condition. +func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool { + return Condition(a.t, comp, msgAndArgs...) +} + + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Contains("Hello World", "World", "But 'Hello World' does contain 'World'") +// a.Contains(["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'") +// a.Contains({"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { + return Contains(a.t, s, contains, msgAndArgs...) +} + + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.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...) +} + + +// Equal asserts that two objects are equal. +// +// a.Equal(123, 123, "123 and 123 should be equal") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + return Equal(a.t, expected, actual, 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(t, err, "An error was expected") { +// assert.Equal(t, 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...) +} + + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.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 interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + return EqualValues(a.t, expected, actual, msgAndArgs...) +} + + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Error(err, "An error was expected") { +// assert.Equal(t, err, expectedError) +// } +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { + return Error(a.t, err, msgAndArgs...) +} + + +// Exactly asserts that two objects are equal is value and type. +// +// a.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 interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + return Exactly(a.t, expected, actual, msgAndArgs...) +} + + +// Fail reports a failure through +func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool { + return Fail(a.t, failureMessage, msgAndArgs...) +} + + +// FailNow fails test +func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool { + return FailNow(a.t, failureMessage, msgAndArgs...) +} + + +// False asserts that the specified value is false. +// +// a.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...) +} + + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContains(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, method string, url string, values url.Values, str interface{}) bool { + return HTTPBodyContains(a.t, handler, method, url, values, str) +} + + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContains(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, method string, url string, values url.Values, str interface{}) bool { + return HTTPBodyNotContains(a.t, handler, method, url, values, str) +} + + +// HTTPError asserts that a specified handler returns an error status code. +// +// a.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, method string, url string, values url.Values) bool { + return HTTPError(a.t, handler, method, url, values) +} + + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// a.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, method string, url string, values url.Values) bool { + return HTTPRedirect(a.t, handler, method, url, values) +} + + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// a.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, method string, url string, values url.Values) bool { + return HTTPSuccess(a.t, handler, method, url, values) +} + + +// Implements asserts that an object is implemented by the specified interface. +// +// a.Implements((*MyInterface)(nil), new(MyObject), "MyObject") +func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { + return Implements(a.t, interfaceObject, object, msgAndArgs...) +} + + +// InDelta asserts that the two numerals are within delta of each other. +// +// a.InDelta(math.Pi, (22 / 7.0), 0.01) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + return InDelta(a.t, expected, actual, delta, msgAndArgs...) +} + + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + return InDeltaSlice(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 interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { + return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) +} + + +// InEpsilonSlice is the same as InEpsilon, except it compares two slices. +func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + return InEpsilonSlice(a.t, expected, actual, delta, 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...) +} + + +// JSONEq asserts that two JSON strings are equivalent. +// +// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { + return JSONEq(a.t, expected, actual, msgAndArgs...) +} + + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// a.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...) +} + + +// Nil asserts that the specified object is nil. +// +// a.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...) +} + + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoError(err) { +// assert.Equal(t, actualObj, expectedObj) +// } +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { + return NoError(a.t, err, msgAndArgs...) +} + + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") +// a.NotContains(["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'") +// a.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 interface{}, contains interface{}, msgAndArgs ...interface{}) bool { + return NotContains(a.t, s, contains, msgAndArgs...) +} + + +// 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 a.NotEmpty(obj) { +// assert.Equal(t, "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...) +} + + +// NotEqual asserts that the specified values are NOT equal. +// +// a.NotEqual(obj1, obj2, "two objects shouldn't be equal") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + return NotEqual(a.t, expected, actual, msgAndArgs...) +} + + +// NotNil asserts that the specified object is not nil. +// +// a.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...) +} + + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.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...) +} + + +// NotRegexp asserts that a specified regexp does not match a string. +// +// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") +// a.NotRegexp("^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...) +} + + +// NotZero asserts that i is not the zero value for its type and returns the truth. +func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool { + return NotZero(a.t, i, msgAndArgs...) +} + + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// a.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...) +} + + +// Regexp asserts that a specified regexp matches a string. +// +// a.Regexp(regexp.MustCompile("start"), "it's starting") +// a.Regexp("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...) +} + + +// True asserts that the specified value is true. +// +// a.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...) +} + + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// a.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 time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { + return WithinDuration(a.t, expected, actual, delta, msgAndArgs...) +} + + +// Zero asserts that i is the zero value for its type and returns the truth. +func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool { + return Zero(a.t, i, msgAndArgs...) +} diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertion_forward.go.tmpl b/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertion_forward.go.tmpl new file mode 100644 index 0000000000..99f9acfbba --- /dev/null +++ b/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertion_forward.go.tmpl @@ -0,0 +1,4 @@ +{{.CommentWithoutT "a"}} +func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { + return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) +} diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go b/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go index e95357d29c..d7c16c5903 100644 --- a/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go +++ b/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go @@ -181,6 +181,28 @@ func indentMessageLines(message string, tabs int) string { return outBuf.String() } +type failNower interface { + FailNow() +} + +// FailNow fails test +func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { + Fail(t, failureMessage, msgAndArgs...) + + // We cannot extend TestingT with FailNow() and + // maintain backwards compatibility, so we fallback + // to panicking when FailNow is not available in + // TestingT. + // See issue #263 + + if t, ok := t.(failNower); ok { + t.FailNow() + } else { + panic("test failed and t is missing `FailNow()`") + } + return false +} + // Fail reports a failure through func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { @@ -363,6 +385,11 @@ func isEmpty(object interface{}) bool { { return (objValue.Len() == 0) } + case reflect.Struct: + switch object.(type) { + case time.Time: + return object.(time.Time).IsZero() + } case reflect.Ptr: { if objValue.IsNil() { @@ -739,42 +766,40 @@ func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAn return true } -// min(|expected|, |actual|) * epsilon -func calcEpsilonDelta(expected, actual interface{}, epsilon float64) float64 { +func calcRelativeError(expected, actual interface{}) (float64, error) { af, aok := toFloat(expected) + if !aok { + return 0, fmt.Errorf("expected value %q cannot be converted to float", expected) + } + if af == 0 { + return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error") + } bf, bok := toFloat(actual) - - if !aok || !bok { - // invalid input - return 0 + if !bok { + return 0, fmt.Errorf("expected value %q cannot be converted to float", actual) } - 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 + return math.Abs(af-bf) / math.Abs(af), nil } // 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) + actualEpsilon, err := calcRelativeError(expected, actual) + if err != nil { + return Fail(t, err.Error(), msgAndArgs...) + } + if actualEpsilon > epsilon { + return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+ + " < %#v (actual)", actualEpsilon, epsilon), msgAndArgs...) + } - return InDelta(t, expected, actual, delta, msgAndArgs...) + return true } -// InEpsilonSlice is the same as InEpsilon, except it compares two slices. -func InEpsilonSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { if expected == nil || actual == nil || reflect.TypeOf(actual).Kind() != reflect.Slice || reflect.TypeOf(expected).Kind() != reflect.Slice { @@ -785,7 +810,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, delta float64, msg expectedSlice := reflect.ValueOf(expected) for i := 0; i < actualSlice.Len(); i++ { - result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta) + result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon) if !result { return result } diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions.go b/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions.go index fe6b664e07..b867e95ea5 100644 --- a/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions.go +++ b/Godeps/_workspace/src/github.com/stretchr/testify/assert/forward_assertions.go @@ -1,7 +1,5 @@ package assert -import "time" - // Assertions provides assertion methods around the // TestingT interface. type Assertions struct { @@ -15,270 +13,4 @@ func New(t TestingT) *Assertions { } } -// 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 false. -// -// 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...) -} - -// Zero asserts that i is the zero value for its type and returns the truth. -func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool { - return Zero(a.t, i, msgAndArgs...) -} - -// NotZero asserts that i is not the zero value for its type and returns the truth. -func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool { - return NotZero(a.t, i, msgAndArgs...) -} - -// JSONEq asserts that two JSON strings are equivalent. -// -// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { - return JSONEq(a.t, expected, actual, msgAndArgs...) -} +//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions.go b/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions.go index 437a86ce47..e1b9442b5a 100644 --- a/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions.go +++ b/Godeps/_workspace/src/github.com/stretchr/testify/assert/http_assertions.go @@ -104,54 +104,3 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url strin 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, method, url string, values url.Values) bool { - return HTTPSuccess(a.t, handler, method, 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, method, url string, values url.Values) bool { - return HTTPRedirect(a.t, handler, method, 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, method, url string, values url.Values) bool { - return HTTPError(a.t, handler, method, 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, method, url string, values url.Values, str interface{}) bool { - return HTTPBodyContains(a.t, handler, method, 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, method, url string, values url.Values, str interface{}) bool { - return HTTPBodyNotContains(a.t, handler, method, url, values, str) -} diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/mock/doc.go b/Godeps/_workspace/src/github.com/stretchr/testify/mock/doc.go index dd385074bc..7324128ef1 100644 --- a/Godeps/_workspace/src/github.com/stretchr/testify/mock/doc.go +++ b/Godeps/_workspace/src/github.com/stretchr/testify/mock/doc.go @@ -1,4 +1,5 @@ -// Provides a system by which it is possible to mock your objects and verify calls are happening as expected. +// Package mock provides a system by which it is possible to mock your objects +// and verify calls are happening as expected. // // Example Usage // diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go b/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go index bc6c86bc50..637896b434 100644 --- a/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go +++ b/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go @@ -17,6 +17,7 @@ import ( type TestingT interface { Logf(format string, args ...interface{}) Errorf(format string, args ...interface{}) + FailNow() } /* @@ -64,64 +65,67 @@ func newCall(parent *Mock, methodName string, methodArguments ...interface{}) *C } } -func (self *Call) lock() { - self.Parent.mutex.Lock() +func (c *Call) lock() { + c.Parent.mutex.Lock() } -func (self *Call) unlock() { - self.Parent.mutex.Unlock() +func (c *Call) unlock() { + c.Parent.mutex.Unlock() } -func (self *Call) Return(returnArguments ...interface{}) *Call { - self.lock() - defer self.unlock() +// Return specifies the return arguments for the expectation. +// +// Mock.On("DoSomething").Return(errors.New("failed")) +func (c *Call) Return(returnArguments ...interface{}) *Call { + c.lock() + defer c.unlock() - self.ReturnArguments = returnArguments + c.ReturnArguments = returnArguments - return self + return c } // Once indicates that that the mock should only return the value once. // // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() -func (self *Call) Once() *Call { - return self.Times(1) +func (c *Call) Once() *Call { + return c.Times(1) } // Twice indicates that that the mock should only return the value twice. // // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice() -func (self *Call) Twice() *Call { - return self.Times(2) +func (c *Call) Twice() *Call { + return c.Times(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 (self *Call) Times(i int) *Call { - self.lock() - defer self.unlock() - self.Repeatability = i - return self +func (c *Call) Times(i int) *Call { + c.lock() + defer c.unlock() + c.Repeatability = i + return c } // 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 (self *Call) WaitUntil(w <-chan time.Time) *Call { - self.lock() - defer self.unlock() - self.WaitFor = w - return self +func (c *Call) WaitUntil(w <-chan time.Time) *Call { + c.lock() + defer c.unlock() + c.WaitFor = w + return c } // After sets how long to block until the call returns // // Mock.On("MyMethod", arg1, arg2).After(time.Second) -func (self *Call) After(d time.Duration) *Call { - return self.WaitUntil(time.After(d)) +func (c *Call) After(d time.Duration) *Call { + return c.WaitUntil(time.After(d)) } // Run sets a handler to be called before returning. It can be used when @@ -132,11 +136,11 @@ func (self *Call) After(d time.Duration) *Call { // arg := args.Get(0).(*map[string]interface{}) // arg["foo"] = "bar" // }) -func (self *Call) Run(fn func(Arguments)) *Call { - self.lock() - defer self.unlock() - self.RunFn = fn - return self +func (c *Call) Run(fn func(Arguments)) *Call { + c.lock() + defer c.unlock() + c.RunFn = fn + return c } // On chains a new expectation description onto the mocked interface. This @@ -145,8 +149,8 @@ func (self *Call) Run(fn func(Arguments)) *Call { // Mock. // On("MyMethod", 1).Return(nil). // On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error")) -func (self *Call) On(methodName string, arguments ...interface{}) *Call { - return self.Parent.On(methodName, arguments...) +func (c *Call) On(methodName string, arguments ...interface{}) *Call { + return c.Parent.On(methodName, arguments...) } // Mock is the workhorse used to track activity on another object. @@ -186,17 +190,17 @@ func (m *Mock) TestData() objx.Map { // being called. // // Mock.On("MyMethod", arg1, arg2) -func (self *Mock) On(methodName string, arguments ...interface{}) *Call { +func (m *Mock) On(methodName string, arguments ...interface{}) *Call { 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)) } } - self.mutex.Lock() - defer self.mutex.Unlock() - c := newCall(self, methodName, arguments...) - self.ExpectedCalls = append(self.ExpectedCalls, c) + m.mutex.Lock() + defer m.mutex.Unlock() + c := newCall(m, methodName, arguments...) + m.ExpectedCalls = append(m.ExpectedCalls, c) return c } @@ -222,7 +226,7 @@ func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, * func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) { diffCount := 0 - var closestCall *Call = nil + var closestCall *Call for _, call := range m.expectedCalls() { if call.Method == method { @@ -245,7 +249,7 @@ func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, * func callString(method string, arguments Arguments, includeArgumentValues bool) string { - var argValsString string = "" + var argValsString string if includeArgumentValues { var argVals []string for argIndex, arg := range arguments { @@ -303,7 +307,7 @@ func (m *Mock) Called(arguments ...interface{}) Arguments { call.Repeatability = -1 case call.Repeatability > 1: - call.Repeatability -= 1 + call.Repeatability-- } m.mutex.Unlock() } @@ -334,7 +338,7 @@ func (m *Mock) Called(arguments ...interface{}) Arguments { // // Calls may have occurred in any order. func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { - var success bool = true + var success = true for _, obj := range testObjects { mockObj := obj.(Mock) success = success && mockObj.AssertExpectations(t) @@ -345,8 +349,8 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { // 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 + var somethingMissing bool + var failedExpectations int // iterate through each expectation expectedCalls := m.expectedCalls() @@ -376,7 +380,7 @@ func (m *Mock) AssertExpectations(t TestingT) bool { // AssertNumberOfCalls asserts that the method was called expectedCalls times. func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool { - var actualCalls int = 0 + var actualCalls int for _, call := range m.calls() { if call.Method == methodName { actualCalls++ @@ -440,8 +444,8 @@ func (m *Mock) calls() []Call { type Arguments []interface{} const ( - // The "any" argument. Used in Diff and Assert when - // the argument being tested shouldn't be taken into consideration. + // Anything is used in Diff and Assert when the argument being tested + // shouldn't be taken into consideration. Anything string = "mock.Anything" ) @@ -471,9 +475,8 @@ func (f argumentMatcher) Matches(argument interface{}) bool { if reflect.TypeOf(argument).AssignableTo(expectType) { result := f.fn.Call([]reflect.Value{reflect.ValueOf(argument)}) return result[0].Bool() - } else { - return false } + return false } func (f argumentMatcher) String() string { @@ -531,10 +534,10 @@ func (args Arguments) Is(objects ...interface{}) bool { // Returns the diff string and number of differences found. func (args Arguments) Diff(objects []interface{}) (string, int) { - var output string = "\n" + var output = "\n" var differences int - var maxArgCount int = len(args) + var maxArgCount = len(args) if len(objects) > maxArgCount { maxArgCount = len(objects) } @@ -629,7 +632,7 @@ func (args Arguments) String(indexOrNil ...int) string { 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 index = indexOrNil[0] var s string var ok bool if s, ok = args.Get(index).(string); !ok { diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/LICENSE b/Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/LICENSE new file mode 100644 index 0000000000..2a7cfd2bf6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2012-2013 Dave Collins + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/LICENSE b/Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/LICENSE new file mode 100644 index 0000000000..c67dad612a --- /dev/null +++ b/Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013, Patrick Mezard +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + The names of its contributors may not be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/stretchr/objx/LICENSE.md b/Godeps/_workspace/src/github.com/stretchr/testify/vendor/github.com/stretchr/objx/LICENSE.md new file mode 100644 index 0000000000..2199945813 --- /dev/null +++ b/Godeps/_workspace/src/github.com/stretchr/testify/vendor/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. diff --git a/api/handlers.go b/api/handlers.go index 19cc4bc562..ce10183ba2 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -14,7 +14,7 @@ import ( "strings" "time" - dockerfilters "github.com/docker/docker/api/types/filters" + dockerfilters "github.com/docker/engine-api/types/filters" "github.com/docker/swarm/cluster" "github.com/docker/swarm/version" "github.com/gorilla/mux" diff --git a/cli/join.go b/cli/join.go index e302e15f73..df8c64d245 100644 --- a/cli/join.go +++ b/cli/join.go @@ -7,7 +7,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" - "github.com/docker/swarm/discovery" + "github.com/docker/docker/pkg/discovery" ) func checkAddrFormat(addr string) bool { diff --git a/cli/list.go b/cli/list.go index 24e9db5467..8e9bc23a12 100644 --- a/cli/list.go +++ b/cli/list.go @@ -6,7 +6,7 @@ import ( "time" "github.com/codegangsta/cli" - "github.com/docker/swarm/discovery" + "github.com/docker/docker/pkg/discovery" ) func list(c *cli.Context) { diff --git a/cli/manage.go b/cli/manage.go index 550baa07db..baca69b45d 100644 --- a/cli/manage.go +++ b/cli/manage.go @@ -11,12 +11,12 @@ import ( log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" + "github.com/docker/docker/pkg/discovery" + kvdiscovery "github.com/docker/docker/pkg/discovery/kv" "github.com/docker/swarm/api" "github.com/docker/swarm/cluster" "github.com/docker/swarm/cluster/mesos" "github.com/docker/swarm/cluster/swarm" - "github.com/docker/swarm/discovery" - kvdiscovery "github.com/docker/swarm/discovery/kv" "github.com/docker/swarm/leadership" "github.com/docker/swarm/scheduler" "github.com/docker/swarm/scheduler/filter" @@ -98,7 +98,7 @@ func loadTLSConfig(ca, cert, key string, verify bool) (*tls.Config, error) { } // Initialize the discovery service. -func createDiscovery(uri string, c *cli.Context, discoveryOpt []string) discovery.Discovery { +func createDiscovery(uri string, c *cli.Context, discoveryOpt []string) discovery.Backend { hb, err := time.ParseDuration(c.String("heartbeat")) if err != nil { log.Fatalf("invalid --heartbeat: %v", err) @@ -126,10 +126,13 @@ func getDiscoveryOpt(c *cli.Context) map[string]string { kvpair := strings.SplitN(option, "=", 2) options[kvpair[0]] = kvpair[1] } + if _, ok := options["kv.path"]; !ok { + options["kv.path"] = "docker/swarm/nodes" + } return options } -func setupReplication(c *cli.Context, cluster cluster.Cluster, server *api.Server, discovery discovery.Discovery, addr string, leaderTTL time.Duration, tlsConfig *tls.Config) { +func setupReplication(c *cli.Context, cluster cluster.Cluster, server *api.Server, discovery discovery.Backend, addr string, leaderTTL time.Duration, tlsConfig *tls.Config) { kvDiscovery, ok := discovery.(*kvdiscovery.Discovery) if !ok { log.Fatal("Leader election is only supported with consul, etcd and zookeeper discovery.") diff --git a/cluster/image.go b/cluster/image.go index 61da20306a..20fddea7cc 100644 --- a/cluster/image.go +++ b/cluster/image.go @@ -3,7 +3,7 @@ package cluster import ( "strings" - dockerfilters "github.com/docker/docker/api/types/filters" + dockerfilters "github.com/docker/engine-api/types/filters" "github.com/samalba/dockerclient" ) diff --git a/cluster/image_test.go b/cluster/image_test.go index 0e6af74899..410fba1203 100644 --- a/cluster/image_test.go +++ b/cluster/image_test.go @@ -3,7 +3,7 @@ package cluster import ( "testing" - dockerfilters "github.com/docker/docker/api/types/filters" + dockerfilters "github.com/docker/engine-api/types/filters" "github.com/samalba/dockerclient" "github.com/stretchr/testify/assert" ) diff --git a/cluster/swarm/cluster.go b/cluster/swarm/cluster.go index 969d28f497..96985b7807 100644 --- a/cluster/swarm/cluster.go +++ b/cluster/swarm/cluster.go @@ -12,10 +12,10 @@ import ( "time" log "github.com/Sirupsen/logrus" + "github.com/docker/docker/pkg/discovery" "github.com/docker/docker/pkg/stringid" "github.com/docker/go-units" "github.com/docker/swarm/cluster" - "github.com/docker/swarm/discovery" "github.com/docker/swarm/scheduler" "github.com/docker/swarm/scheduler/node" "github.com/samalba/dockerclient" @@ -54,7 +54,7 @@ type Cluster struct { engines map[string]*cluster.Engine pendingEngines map[string]*cluster.Engine scheduler *scheduler.Scheduler - discovery discovery.Discovery + discovery discovery.Backend pendingContainers map[string]*pendingContainer overcommitRatio float64 @@ -63,7 +63,7 @@ type Cluster struct { } // NewCluster is exported -func NewCluster(scheduler *scheduler.Scheduler, TLSConfig *tls.Config, discovery discovery.Discovery, options cluster.DriverOpts, engineOptions *cluster.EngineOpts) (cluster.Cluster, error) { +func NewCluster(scheduler *scheduler.Scheduler, TLSConfig *tls.Config, discovery discovery.Backend, options cluster.DriverOpts, engineOptions *cluster.EngineOpts) (cluster.Cluster, error) { log.WithFields(log.Fields{"name": "swarm"}).Debug("Initializing cluster") cluster := &Cluster{ diff --git a/discovery/discovery.go b/discovery/discovery.go deleted file mode 100644 index 1888d1a0f4..0000000000 --- a/discovery/discovery.go +++ /dev/null @@ -1,166 +0,0 @@ -package discovery - -import ( - "errors" - "fmt" - "net" - "strings" - "time" - - log "github.com/Sirupsen/logrus" -) - -// An Entry represents a swarm host. -type Entry struct { - Host string - Port string -} - -// NewEntry creates a new entry. -func NewEntry(url string) (*Entry, error) { - host, port, err := net.SplitHostPort(url) - if err != nil { - return nil, err - } - return &Entry{host, port}, nil -} - -// String returns the string form of an entry. -func (e *Entry) String() string { - return fmt.Sprintf("%s:%s", e.Host, e.Port) -} - -// 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 -} - -// 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 { - // Initialize the discovery with URIs, a heartbeat, a ttl and optional settings. - Initialize(string, time.Duration, time.Duration, map[string]string) 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 -} - -var ( - discoveries map[string]Discovery - // ErrNotSupported is returned when a discovery service is not supported. - ErrNotSupported = errors.New("discovery service not supported") - // ErrNotImplemented is returned when discovery feature is not implemented - // by discovery backend. - ErrNotImplemented = errors.New("not implemented in this discovery service") -) - -func init() { - discoveries = make(map[string]Discovery) -} - -// 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 { - if _, exists := discoveries[scheme]; exists { - return fmt.Errorf("scheme already registered %s", scheme) - } - log.WithField("name", scheme).Debug("Registering discovery service") - discoveries[scheme] = d - - return nil -} - -func parse(rawurl string) (string, string) { - parts := strings.SplitN(rawurl, "://", 2) - - // nodes:port,node2:port => nodes://node1:port,node2:port - if len(parts) == 1 { - return "nodes", parts[0] - } - return parts[0], parts[1] -} - -// 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, discoveryOpt map[string]string) (Discovery, error) { - scheme, uri := parse(rawurl) - - if discovery, exists := discoveries[scheme]; exists { - log.WithFields(log.Fields{"name": scheme, "uri": uri}).Debug("Initializing discovery service") - err := discovery.Initialize(uri, heartbeat, ttl, discoveryOpt) - return discovery, err - } - - return nil, ErrNotSupported -} - -// CreateEntries returns an array of entries based on the given addresses. -func CreateEntries(addrs []string) (Entries, error) { - entries := Entries{} - if addrs == nil { - return entries, nil - } - - for _, addr := range addrs { - if len(addr) == 0 { - continue - } - entry, err := NewEntry(addr) - if err != nil { - return nil, err - } - entries = append(entries, entry) - } - return entries, nil -} diff --git a/discovery/discovery_test.go b/discovery/discovery_test.go deleted file mode 100644 index b7128ff258..0000000000 --- a/discovery/discovery_test.go +++ /dev/null @@ -1,120 +0,0 @@ -package discovery - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestNewEntry(t *testing.T) { - entry, err := NewEntry("127.0.0.1:2375") - 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") - assert.Error(t, err) -} - -func TestParse(t *testing.T) { - scheme, uri := parse("127.0.0.1:2375") - assert.Equal(t, scheme, "nodes") - assert.Equal(t, uri, "127.0.0.1:2375") - - scheme, uri = parse("localhost:2375") - assert.Equal(t, scheme, "nodes") - assert.Equal(t, uri, "localhost:2375") - - scheme, uri = parse("scheme://127.0.0.1:2375") - assert.Equal(t, scheme, "scheme") - assert.Equal(t, uri, "127.0.0.1:2375") - - scheme, uri = parse("scheme://localhost:2375") - assert.Equal(t, scheme, "scheme") - assert.Equal(t, uri, "localhost:2375") - - scheme, uri = parse("") - assert.Equal(t, scheme, "nodes") - assert.Equal(t, uri, "") -} - -func TestCreateEntries(t *testing.T) { - entries, err := CreateEntries(nil) - assert.Equal(t, entries, Entries{}) - assert.NoError(t, err) - - entries, err = CreateEntries([]string{"127.0.0.1:2375", "127.0.0.2:2375", ""}) - 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"}) - 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)) -} diff --git a/discovery/file/file_test.go b/discovery/file/file_test.go deleted file mode 100644 index 05f248fb87..0000000000 --- a/discovery/file/file_test.go +++ /dev/null @@ -1,106 +0,0 @@ -package file - -import ( - "io/ioutil" - "os" - "testing" - - "github.com/docker/swarm/discovery" - "github.com/stretchr/testify/assert" -) - -func TestInitialize(t *testing.T) { - d := &Discovery{} - d.Initialize("/path/to/file", 1000, 0, nil) - assert.Equal(t, d.path, "/path/to/file") -} - -func TestNew(t *testing.T) { - d, err := discovery.New("file:///path/to/file", 0, 0, nil) - assert.NoError(t, err) - assert.Equal(t, d.(*Discovery).path, "/path/to/file") -} - -func TestContent(t *testing.T) { - data := ` -1.1.1.[1:2]:1111 -2.2.2.[2:4]:2222 -` - ips := parseFileContent([]byte(data)) - assert.Len(t, ips, 5) - assert.Equal(t, ips[0], "1.1.1.1: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[3], "2.2.2.3:2222") - assert.Equal(t, ips[4], "2.2.2.4:2222") -} - -func TestRegister(t *testing.T) { - discovery := &Discovery{path: "/path/to/file"} - assert.Error(t, discovery.Register("0.0.0.0")) -} - -func TestParsingContentsWithComments(t *testing.T) { - data := ` -### test ### -1.1.1.1:1111 # inline comment -# 2.2.2.2:2222 - ### empty line with comment - 3.3.3.3:3333 -### test ### -` - ips := parseFileContent([]byte(data)) - assert.Len(t, ips, 2) - assert.Equal(t, "1.1.1.1:1111", ips[0]) - 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, nil) - 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) -} diff --git a/discovery/generator_test.go b/discovery/generator_test.go deleted file mode 100644 index 747334452f..0000000000 --- a/discovery/generator_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package discovery - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGeneratorNotGenerate(t *testing.T) { - ips := Generate("127.0.0.1") - assert.Equal(t, len(ips), 1) - assert.Equal(t, ips[0], "127.0.0.1") -} - -func TestGeneratorWithPortNotGenerate(t *testing.T) { - ips := Generate("127.0.0.1:8080") - assert.Equal(t, len(ips), 1) - assert.Equal(t, ips[0], "127.0.0.1:8080") -} - -func TestGeneratorMatchFailedNotGenerate(t *testing.T) { - ips := Generate("127.0.0.[1]") - assert.Equal(t, len(ips), 1) - assert.Equal(t, ips[0], "127.0.0.[1]") -} - -func TestGeneratorWithPort(t *testing.T) { - ips := Generate("127.0.0.[1:11]:2375") - assert.Equal(t, len(ips), 11) - assert.Equal(t, ips[0], "127.0.0.1:2375") - assert.Equal(t, ips[1], "127.0.0.2:2375") - assert.Equal(t, ips[2], "127.0.0.3:2375") - assert.Equal(t, ips[3], "127.0.0.4:2375") - assert.Equal(t, ips[4], "127.0.0.5:2375") - assert.Equal(t, ips[5], "127.0.0.6:2375") - assert.Equal(t, ips[6], "127.0.0.7:2375") - assert.Equal(t, ips[7], "127.0.0.8:2375") - assert.Equal(t, ips[8], "127.0.0.9:2375") - assert.Equal(t, ips[9], "127.0.0.10:2375") - assert.Equal(t, ips[10], "127.0.0.11:2375") -} - -func TestGenerateWithMalformedInputAtRangeStart(t *testing.T) { - malformedInput := "127.0.0.[x:11]:2375" - ips := Generate(malformedInput) - assert.Equal(t, len(ips), 1) - assert.Equal(t, ips[0], malformedInput) -} - -func TestGenerateWithMalformedInputAtRangeEnd(t *testing.T) { - malformedInput := "127.0.0.[1:x]:2375" - ips := Generate(malformedInput) - assert.Equal(t, len(ips), 1) - assert.Equal(t, ips[0], malformedInput) -} diff --git a/discovery/kv/kv_test.go b/discovery/kv/kv_test.go deleted file mode 100644 index 045559c276..0000000000 --- a/discovery/kv/kv_test.go +++ /dev/null @@ -1,199 +0,0 @@ -package kv - -import ( - "errors" - "io/ioutil" - "os" - "path" - "testing" - "time" - - "github.com/docker/libkv" - "github.com/docker/libkv/store" - libkvmock "github.com/docker/libkv/store/mock" - "github.com/docker/swarm/discovery" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestInitialize(t *testing.T) { - storeMock, err := libkvmock.New([]string{"127.0.0.1"}, nil) - assert.NotNil(t, storeMock) - assert.NoError(t, err) - - d := &Discovery{backend: store.CONSUL} - d.Initialize("127.0.0.1", 0, 0, nil) - d.store = storeMock - - s := d.store.(*libkvmock.Mock) - assert.Len(t, s.Endpoints, 1) - assert.Equal(t, s.Endpoints[0], "127.0.0.1") - assert.Equal(t, d.path, defaultDiscoveryPath) - - storeMock, err = libkvmock.New([]string{"127.0.0.1:1234"}, nil) - assert.NotNil(t, storeMock) - assert.NoError(t, err) - - d = &Discovery{backend: store.CONSUL} - d.Initialize("127.0.0.1:1234/path", 0, 0, nil) - d.store = storeMock - - s = d.store.(*libkvmock.Mock) - assert.Len(t, s.Endpoints, 1) - assert.Equal(t, s.Endpoints[0], "127.0.0.1:1234") - assert.Equal(t, d.path, "path/"+defaultDiscoveryPath) - - storeMock, err = libkvmock.New([]string{"127.0.0.1:1234", "127.0.0.2:1234", "127.0.0.3:1234"}, nil) - assert.NotNil(t, storeMock) - assert.NoError(t, err) - - d = &Discovery{backend: store.CONSUL} - d.Initialize("127.0.0.1:1234,127.0.0.2:1234,127.0.0.3:1234/path", 0, 0, nil) - d.store = storeMock - - s = d.store.(*libkvmock.Mock) - if 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/"+defaultDiscoveryPath) -} - -func TestInitializeWithCerts(t *testing.T) { - cert := `-----BEGIN CERTIFICATE----- -MIIDCDCCAfKgAwIBAgIICifG7YeiQOEwCwYJKoZIhvcNAQELMBIxEDAOBgNVBAMT -B1Rlc3QgQ0EwHhcNMTUxMDAxMjMwMDAwWhcNMjAwOTI5MjMwMDAwWjASMRAwDgYD -VQQDEwdUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1wRC -O+flnLTK5ImjTurNRHwSejuqGbc4CAvpB0hS+z0QlSs4+zE9h80aC4hz+6caRpds -+J908Q+RvAittMHbpc7VjbZP72G6fiXk7yPPl6C10HhRSoSi3nY+B7F2E8cuz14q -V2e+ejhWhSrBb/keyXpcyjoW1BOAAJ2TIclRRkICSCZrpXUyXxAvzXfpFXo1RhSb -UywN11pfiCQzDUN7sPww9UzFHuAHZHoyfTr27XnJYVUerVYrCPq8vqfn//01qz55 -Xs0hvzGdlTFXhuabFtQnKFH5SNwo/fcznhB7rePOwHojxOpXTBepUCIJLbtNnWFT -V44t9gh5IqIWtoBReQIDAQABo2YwZDAOBgNVHQ8BAf8EBAMCAAYwEgYDVR0TAQH/ -BAgwBgEB/wIBAjAdBgNVHQ4EFgQUZKUI8IIjIww7X/6hvwggQK4bD24wHwYDVR0j -BBgwFoAUZKUI8IIjIww7X/6hvwggQK4bD24wCwYJKoZIhvcNAQELA4IBAQDES2cz -7sCQfDCxCIWH7X8kpi/JWExzUyQEJ0rBzN1m3/x8ySRxtXyGekimBqQwQdFqlwMI -xzAQKkh3ue8tNSzRbwqMSyH14N1KrSxYS9e9szJHfUasoTpQGPmDmGIoRJuq1h6M -ej5x1SCJ7GWCR6xEXKUIE9OftXm9TdFzWa7Ja3OHz/mXteii8VXDuZ5ACq6EE5bY -8sP4gcICfJ5fTrpTlk9FIqEWWQrCGa5wk95PGEj+GJpNogjXQ97wVoo/Y3p1brEn -t5zjN9PAq4H1fuCMdNNA+p1DHNwd+ELTxcMAnb2ajwHvV6lKPXutrTFc4umJToBX -FpTxDmJHEV4bzUzh ------END CERTIFICATE----- -` - key := `-----BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEA1wRCO+flnLTK5ImjTurNRHwSejuqGbc4CAvpB0hS+z0QlSs4 -+zE9h80aC4hz+6caRpds+J908Q+RvAittMHbpc7VjbZP72G6fiXk7yPPl6C10HhR -SoSi3nY+B7F2E8cuz14qV2e+ejhWhSrBb/keyXpcyjoW1BOAAJ2TIclRRkICSCZr -pXUyXxAvzXfpFXo1RhSbUywN11pfiCQzDUN7sPww9UzFHuAHZHoyfTr27XnJYVUe -rVYrCPq8vqfn//01qz55Xs0hvzGdlTFXhuabFtQnKFH5SNwo/fcznhB7rePOwHoj -xOpXTBepUCIJLbtNnWFTV44t9gh5IqIWtoBReQIDAQABAoIBAHSWipORGp/uKFXj -i/mut776x8ofsAxhnLBARQr93ID+i49W8H7EJGkOfaDjTICYC1dbpGrri61qk8sx -qX7p3v/5NzKwOIfEpirgwVIqSNYe/ncbxnhxkx6tXtUtFKmEx40JskvSpSYAhmmO -1XSx0E/PWaEN/nLgX/f1eWJIlxlQkk3QeqL+FGbCXI48DEtlJ9+MzMu4pAwZTpj5 -5qtXo5JJ0jRGfJVPAOznRsYqv864AhMdMIWguzk6EGnbaCWwPcfcn+h9a5LMdony -MDHfBS7bb5tkF3+AfnVY3IBMVx7YlsD9eAyajlgiKu4zLbwTRHjXgShy+4Oussz0 -ugNGnkECgYEA/hi+McrZC8C4gg6XqK8+9joD8tnyDZDz88BQB7CZqABUSwvjDqlP -L8hcwo/lzvjBNYGkqaFPUICGWKjeCtd8pPS2DCVXxDQX4aHF1vUur0uYNncJiV3N -XQz4Iemsa6wnKf6M67b5vMXICw7dw0HZCdIHD1hnhdtDz0uVpeevLZ8CgYEA2KCT -Y43lorjrbCgMqtlefkr3GJA9dey+hTzCiWEOOqn9RqGoEGUday0sKhiLofOgmN2B -LEukpKIey8s+Q/cb6lReajDVPDsMweX8i7hz3Wa4Ugp4Xa5BpHqu8qIAE2JUZ7bU -t88aQAYE58pUF+/Lq1QzAQdrjjzQBx6SrBxieecCgYEAvukoPZEC8mmiN1VvbTX+ -QFHmlZha3QaDxChB+QUe7bMRojEUL/fVnzkTOLuVFqSfxevaI/km9n0ac5KtAchV -xjp2bTnBb5EUQFqjopYktWA+xO07JRJtMfSEmjZPbbay1kKC7rdTfBm961EIHaRj -xZUf6M+rOE8964oGrdgdLlECgYEA046GQmx6fh7/82FtdZDRQp9tj3SWQUtSiQZc -qhO59Lq8mjUXz+MgBuJXxkiwXRpzlbaFB0Bca1fUoYw8o915SrDYf/Zu2OKGQ/qa -V81sgiVmDuEgycR7YOlbX6OsVUHrUlpwhY3hgfMe6UtkMvhBvHF/WhroBEIJm1pV -PXZ/CbMCgYEApNWVktFBjOaYfY6SNn4iSts1jgsQbbpglg3kT7PLKjCAhI6lNsbk -dyT7ut01PL6RaW4SeQWtrJIVQaM6vF3pprMKqlc5XihOGAmVqH7rQx9rtQB5TicL -BFrwkQE4HQtQBV60hYQUzzlSk44VFDz+jxIEtacRHaomDRh2FtOTz+I= ------END RSA PRIVATE KEY----- -` - certFile, err := ioutil.TempFile("", "cert") - assert.Nil(t, err) - defer os.Remove(certFile.Name()) - certFile.Write([]byte(cert)) - certFile.Close() - keyFile, err := ioutil.TempFile("", "key") - assert.Nil(t, err) - defer os.Remove(keyFile.Name()) - keyFile.Write([]byte(key)) - keyFile.Close() - - libkv.AddStore("mock", libkvmock.New) - d := &Discovery{backend: "mock"} - err = d.Initialize("127.0.0.3:1234", 0, 0, map[string]string{ - "kv.cacertfile": certFile.Name(), - "kv.certfile": certFile.Name(), - "kv.keyfile": keyFile.Name(), - }) - assert.Nil(t, err) - s := d.store.(*libkvmock.Mock) - assert.Equal(t, s.Options.ClientTLS.CACertFile, certFile.Name()) - assert.Equal(t, s.Options.ClientTLS.CertFile, certFile.Name()) - assert.Equal(t, s.Options.ClientTLS.KeyFile, keyFile.Name()) -} - -func TestWatch(t *testing.T) { - storeMock, err := libkvmock.New([]string{"127.0.0.1:1234"}, nil) - assert.NotNil(t, storeMock) - assert.NoError(t, err) - - d := &Discovery{backend: store.CONSUL} - d.Initialize("127.0.0.1:1234/path", 0, 0, nil) - d.store = storeMock - - s := d.store.(*libkvmock.Mock) - mockCh := make(chan []*store.KVPair) - - // The first watch will fail on those three calls - s.On("Exists", "path/"+defaultDiscoveryPath).Return(false, errors.New("test error")) - s.On("Put", "path/"+defaultDiscoveryPath, mock.Anything, mock.Anything).Return(errors.New("test error")) - s.On("WatchTree", "path/"+defaultDiscoveryPath, mock.Anything).Return(mockCh, errors.New("test error")).Once() - - // The second one will succeed. - s.On("WatchTree", "path/"+defaultDiscoveryPath, 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", defaultDiscoveryPath, "1.1.1.1"), Value: []byte("1.1.1.1:1111")}, - {Key: path.Join("path", defaultDiscoveryPath, "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 WatchTree 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", defaultDiscoveryPath, "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/"+defaultDiscoveryPath, mock.Anything).Return(mockCh, nil) - close(mockCh) - // Give it enough time to call WatchTree. - time.Sleep(3) - - // Stop and make sure it closes all channels. - close(stopCh) - assert.Nil(t, <-ch) - assert.Nil(t, <-errCh) - - s.AssertExpectations(t) -} diff --git a/discovery/nodes/nodes_test.go b/discovery/nodes/nodes_test.go deleted file mode 100644 index dd1ed4fe26..0000000000 --- a/discovery/nodes/nodes_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package nodes - -import ( - "testing" - - "github.com/docker/swarm/discovery" - "github.com/stretchr/testify/assert" -) - -func TestInitialize(t *testing.T) { - d := &Discovery{} - d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0, nil) - 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 TestInitializeWithPattern(t *testing.T) { - d := &Discovery{} - d.Initialize("1.1.1.[1:2]:1111,2.2.2.[2:4]:2222", 0, 0, nil) - 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, nil) - 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) { - d := &Discovery{} - assert.Error(t, d.Register("0.0.0.0")) -} diff --git a/discovery/token/token.go b/discovery/token/token.go index 1f08e516a3..a416fe2035 100644 --- a/discovery/token/token.go +++ b/discovery/token/token.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/docker/swarm/discovery" + "github.com/docker/docker/pkg/discovery" ) const discoveryURL = "https://discovery.hub.docker.com/v1" diff --git a/discovery/token/token_test.go b/discovery/token/token_test.go index d3c08d8f88..d3c29e32aa 100644 --- a/discovery/token/token_test.go +++ b/discovery/token/token_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "github.com/docker/swarm/discovery" + "github.com/docker/docker/pkg/discovery" "github.com/stretchr/testify/assert" ) diff --git a/docs/discovery.md b/docs/discovery.md index f111281c75..7670fe8d30 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -209,8 +209,9 @@ swarm is connected to the public internet. To create your swarm: You can contribute a new discovery backend to Swarm. For information on how to do this, see our -discovery README in the Docker Swarm repository. +href="https://github.com/docker/docker/tree/master/pkg/discovery"> +github.com/docker/docker/pkg/discovery. + ## Docker Swarm documentation index diff --git a/main.go b/main.go index f90922793d..e59a0637cc 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,9 @@ package main import ( - _ "github.com/docker/swarm/discovery/file" - _ "github.com/docker/swarm/discovery/kv" - _ "github.com/docker/swarm/discovery/nodes" + _ "github.com/docker/docker/pkg/discovery/file" + _ "github.com/docker/docker/pkg/discovery/kv" + _ "github.com/docker/docker/pkg/discovery/nodes" _ "github.com/docker/swarm/discovery/token" "github.com/docker/swarm/cli"