mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 20:53:33 +00:00
Merge pull request #12770 from bparees/master
bump(fsouza/go-dockerclient): 42d06e2b125654477366c320dcea99107a86e9c2
This commit is contained in:
commit
03d961a8b3
2
Godeps/Godeps.json
generated
2
Godeps/Godeps.json
generated
@ -232,7 +232,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/fsouza/go-dockerclient",
|
||||
"Rev": "933433faa3e1c0bbc825b251143f8e77affbf797"
|
||||
"Rev": "42d06e2b125654477366c320dcea99107a86e9c2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/garyburd/redigo/internal",
|
||||
|
5
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/AUTHORS
generated
vendored
5
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/AUTHORS
generated
vendored
@ -8,8 +8,9 @@ Artem Sidorenko <artem@2realities.com>
|
||||
Andy Goldstein <andy.goldstein@redhat.com>
|
||||
Ben Marini <ben@remind101.com>
|
||||
Ben McCann <benmccann.com>
|
||||
Brian Lalor <blalor@bravo5.org>
|
||||
Brendan Fosberry <brendan@codeship.com>
|
||||
Brian Lalor <blalor@bravo5.org>
|
||||
Brian Palmer <brianp@instructure.com>
|
||||
Burke Libbey <burke@libbey.me>
|
||||
Carlos Diaz-Padron <cpadron@mozilla.com>
|
||||
Cezar Sa Espinola <cezar.sa@corp.globo.com>
|
||||
@ -17,6 +18,7 @@ Cheah Chu Yeow <chuyeow@gmail.com>
|
||||
cheneydeng <cheneydeng@qq.com>
|
||||
CMGS <ilskdw@gmail.com>
|
||||
Craig Jellick <craig@rancher.com>
|
||||
Dan Williams <dcbw@redhat.com>
|
||||
Daniel, Dao Quang Minh <dqminh89@gmail.com>
|
||||
Daniel Garcia <daniel@danielgarcia.info>
|
||||
Darren Shepherd <darren@rancher.com>
|
||||
@ -80,6 +82,7 @@ Sunjin Lee <styner32@gmail.com>
|
||||
Tarsis Azevedo <tarsis@corp.globo.com>
|
||||
Tim Schindler <tim@catalyst-zero.com>
|
||||
Tobi Knaup <tobi@mesosphere.io>
|
||||
Tonic <tonicbupt@gmail.com>
|
||||
ttyh061 <ttyh061@gmail.com>
|
||||
Victor Marmol <vmarmol@google.com>
|
||||
Vincenzo Prignano <vincenzo.prignano@gmail.com>
|
||||
|
12
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/README.markdown
generated
vendored
12
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/README.markdown
generated
vendored
@ -7,8 +7,20 @@
|
||||
This package presents a client for the Docker remote API. It also provides
|
||||
support for the extensions in the [Swarm API](https://docs.docker.com/swarm/API/).
|
||||
|
||||
This package also provides support for docker's network API, which is a simple
|
||||
passthrough to the libnetwork remote API. Note that docker's network API is
|
||||
only available in docker 1.8 and above, and only enabled in docker if
|
||||
DOCKER_EXPERIMENTAL is defined during the docker build process.
|
||||
|
||||
For more details, check the [remote API documentation](http://docs.docker.com/en/latest/reference/api/docker_remote_api/).
|
||||
|
||||
## Vendoring
|
||||
|
||||
If you are having issues with Go 1.5 and have `GO15VENDOREXPERIMENT` set with an application that has go-dockerclient vendored,
|
||||
please update your vendoring of go-dockerclient :) We recently moved the `vendor` directory to `external` so that go-dockerclient
|
||||
is compatible with this configuration. See [338](https://github.com/fsouza/go-dockerclient/issues/338) and [339](https://github.com/fsouza/go-dockerclient/pull/339)
|
||||
for details.
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
|
6
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/auth.go
generated
vendored
6
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/auth.go
generated
vendored
@ -8,6 +8,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@ -15,6 +16,8 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var AuthParseError error = errors.New("Failed to read authentication from dockercfg")
|
||||
|
||||
// AuthConfiguration represents authentication options to use in the PushImage
|
||||
// method. It represents the authentication in the Docker index server.
|
||||
type AuthConfiguration struct {
|
||||
@ -99,6 +102,9 @@ func authConfigs(confs map[string]dockerConfig) (*AuthConfigurations, error) {
|
||||
return nil, err
|
||||
}
|
||||
userpass := strings.Split(string(data), ":")
|
||||
if len(userpass) != 2 {
|
||||
return nil, AuthParseError
|
||||
}
|
||||
c.Configs[reg] = AuthConfiguration{
|
||||
Email: conf.Email,
|
||||
Username: userpass[0],
|
||||
|
12
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/auth_test.go
generated
vendored
12
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/auth_test.go
generated
vendored
@ -37,6 +37,18 @@ func TestAuthLegacyConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthBadConfig(t *testing.T) {
|
||||
auth := base64.StdEncoding.EncodeToString([]byte("userpass"))
|
||||
read := strings.NewReader(fmt.Sprintf(`{"docker.io":{"auth":"%s","email":"user@example.com"}}`, auth))
|
||||
ac, err := NewAuthConfigurations(read)
|
||||
if err != AuthParseError {
|
||||
t.Errorf("Incorrect error returned %v\n", err)
|
||||
}
|
||||
if ac != nil {
|
||||
t.Errorf("Invalid auth configuration returned, should be nil %v\n", ac)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthConfig(t *testing.T) {
|
||||
auth := base64.StdEncoding.EncodeToString([]byte("user:pass"))
|
||||
read := strings.NewReader(fmt.Sprintf(`{"auths":{"docker.io":{"auth":"%s","email":"user@example.com"}}}`, auth))
|
||||
|
15
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/client.go
generated
vendored
15
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/client.go
generated
vendored
@ -28,10 +28,11 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/fsouza/go-dockerclient/external/github.com/docker/docker/opts"
|
||||
"github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/homedir"
|
||||
"github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/stdcopy"
|
||||
"time"
|
||||
)
|
||||
|
||||
const userAgent = "go-dockerclient"
|
||||
@ -628,18 +629,20 @@ func (c *Client) hijack(method, path string, hijackOptions hijackOptions) error
|
||||
if hijackOptions.in != nil {
|
||||
_, err := io.Copy(rwc, hijackOptions.in)
|
||||
errChanIn <- err
|
||||
} else {
|
||||
errChanIn <- nil
|
||||
}
|
||||
rwc.(interface {
|
||||
CloseWrite() error
|
||||
}).CloseWrite()
|
||||
}()
|
||||
<-exit
|
||||
select {
|
||||
case err = <-errChanIn:
|
||||
return err
|
||||
case err = <-errChanOut:
|
||||
return err
|
||||
errIn := <-errChanIn
|
||||
errOut := <-errChanOut
|
||||
if errIn != nil {
|
||||
return errIn
|
||||
}
|
||||
return errOut
|
||||
}
|
||||
|
||||
func (c *Client) getURL(path string) string {
|
||||
|
5
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/client_test.go
generated
vendored
5
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/client_test.go
generated
vendored
@ -329,16 +329,17 @@ func TestPingFailingWrongStatus(t *testing.T) {
|
||||
func TestPingErrorWithUnixSocket(t *testing.T) {
|
||||
go func() {
|
||||
li, err := net.Listen("unix", "/tmp/echo.sock")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer li.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("Expected to get listner, but failed: %#v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fd, err := li.Accept()
|
||||
if err != nil {
|
||||
t.Fatalf("Expected to accept connection, but failed: %#v", err)
|
||||
return
|
||||
}
|
||||
|
||||
buf := make([]byte, 512)
|
||||
|
42
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/container.go
generated
vendored
42
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/container.go
generated
vendored
@ -128,13 +128,23 @@ type PortMapping map[string]string
|
||||
|
||||
// NetworkSettings contains network-related information about a container
|
||||
type NetworkSettings struct {
|
||||
IPAddress string `json:"IPAddress,omitempty" yaml:"IPAddress,omitempty"`
|
||||
IPPrefixLen int `json:"IPPrefixLen,omitempty" yaml:"IPPrefixLen,omitempty"`
|
||||
MacAddress string `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty"`
|
||||
Gateway string `json:"Gateway,omitempty" yaml:"Gateway,omitempty"`
|
||||
Bridge string `json:"Bridge,omitempty" yaml:"Bridge,omitempty"`
|
||||
PortMapping map[string]PortMapping `json:"PortMapping,omitempty" yaml:"PortMapping,omitempty"`
|
||||
Ports map[Port][]PortBinding `json:"Ports,omitempty" yaml:"Ports,omitempty"`
|
||||
IPAddress string `json:"IPAddress,omitempty" yaml:"IPAddress,omitempty"`
|
||||
IPPrefixLen int `json:"IPPrefixLen,omitempty" yaml:"IPPrefixLen,omitempty"`
|
||||
MacAddress string `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty"`
|
||||
Gateway string `json:"Gateway,omitempty" yaml:"Gateway,omitempty"`
|
||||
Bridge string `json:"Bridge,omitempty" yaml:"Bridge,omitempty"`
|
||||
PortMapping map[string]PortMapping `json:"PortMapping,omitempty" yaml:"PortMapping,omitempty"`
|
||||
Ports map[Port][]PortBinding `json:"Ports,omitempty" yaml:"Ports,omitempty"`
|
||||
NetworkID string `json:"NetworkID,omitempty" yaml:"NetworkID,omitempty"`
|
||||
EndpointID string `json:"EndpointID,omitempty" yaml:"EndpointID,omitempty"`
|
||||
SandboxKey string `json:"SandboxKey,omitempty" yaml:"SandboxKey,omitempty"`
|
||||
GlobalIPv6Address string `json:"GlobalIPv6Address,omitempty" yaml:"GlobalIPv6Address,omitempty"`
|
||||
GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen,omitempty" yaml:"GlobalIPv6PrefixLen,omitempty"`
|
||||
IPv6Gateway string `json:"IPv6Gateway,omitempty" yaml:"IPv6Gateway,omitempty"`
|
||||
LinkLocalIPv6Address string `json:"LinkLocalIPv6Address,omitempty" yaml:"LinkLocalIPv6Address,omitempty"`
|
||||
LinkLocalIPv6PrefixLen int `json:"LinkLocalIPv6PrefixLen,omitempty" yaml:"LinkLocalIPv6PrefixLen,omitempty"`
|
||||
SecondaryIPAddresses []string `json:"SecondaryIPAddresses,omitempty" yaml:"SecondaryIPAddresses,omitempty"`
|
||||
SecondaryIPv6Addresses []string `json:"SecondaryIPv6Addresses,omitempty" yaml:"SecondaryIPv6Addresses,omitempty"`
|
||||
}
|
||||
|
||||
// PortMappingAPI translates the port mappings as contained in NetworkSettings
|
||||
@ -726,6 +736,18 @@ func (c *Client) Stats(opts StatsOptions) (retErr error) {
|
||||
close(errC)
|
||||
}()
|
||||
|
||||
quit := make(chan struct{})
|
||||
defer close(quit)
|
||||
go func() {
|
||||
// block here waiting for the signal to stop function
|
||||
select {
|
||||
case <-opts.Done:
|
||||
readCloser.Close()
|
||||
case <-quit:
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
decoder := json.NewDecoder(readCloser)
|
||||
stats := new(Stats)
|
||||
for err := decoder.Decode(&stats); err != io.EOF; err = decoder.Decode(stats) {
|
||||
@ -734,12 +756,6 @@ func (c *Client) Stats(opts StatsOptions) (retErr error) {
|
||||
}
|
||||
opts.Stats <- stats
|
||||
stats = new(Stats)
|
||||
select {
|
||||
case <-opts.Done:
|
||||
readCloser.Close()
|
||||
default:
|
||||
// Continue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
11
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/copy_unix.go
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/copy_unix.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
// +build !windows
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func normalizePath(path string) string {
|
||||
return filepath.ToSlash(path)
|
||||
}
|
9
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/copy_windows.go
generated
vendored
Normal file
9
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/copy_windows.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package archive
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func normalizePath(path string) string {
|
||||
return filepath.FromSlash(path)
|
||||
}
|
@ -1,7 +1,235 @@
|
||||
mux
|
||||
===
|
||||
[](https://godoc.org/github.com/gorilla/securecookie)
|
||||
[](https://travis-ci.org/gorilla/mux)
|
||||
|
||||
gorilla/mux is a powerful URL router and dispatcher.
|
||||
Package gorilla/mux implements a request router and dispatcher.
|
||||
|
||||
Read the full documentation here: http://www.gorillatoolkit.org/pkg/mux
|
||||
The name mux stands for "HTTP request multiplexer". Like the standard
|
||||
http.ServeMux, mux.Router matches incoming requests against a list of
|
||||
registered routes and calls a handler for the route that matches the URL
|
||||
or other conditions. The main features are:
|
||||
|
||||
* Requests can be matched based on URL host, path, path prefix, schemes,
|
||||
header and query values, HTTP methods or using custom matchers.
|
||||
* URL hosts and paths can have variables with an optional regular
|
||||
expression.
|
||||
* Registered URLs can be built, or "reversed", which helps maintaining
|
||||
references to resources.
|
||||
* Routes can be used as subrouters: nested routes are only tested if the
|
||||
parent route matches. This is useful to define groups of routes that
|
||||
share common conditions like a host, a path prefix or other repeated
|
||||
attributes. As a bonus, this optimizes request matching.
|
||||
* It implements the http.Handler interface so it is compatible with the
|
||||
standard http.ServeMux.
|
||||
|
||||
Let's start registering a couple of URL paths and handlers:
|
||||
|
||||
func main() {
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/", HomeHandler)
|
||||
r.HandleFunc("/products", ProductsHandler)
|
||||
r.HandleFunc("/articles", ArticlesHandler)
|
||||
http.Handle("/", r)
|
||||
}
|
||||
|
||||
Here we register three routes mapping URL paths to handlers. This is
|
||||
equivalent to how http.HandleFunc() works: if an incoming request URL matches
|
||||
one of the paths, the corresponding handler is called passing
|
||||
(http.ResponseWriter, *http.Request) as parameters.
|
||||
|
||||
Paths can have variables. They are defined using the format {name} or
|
||||
{name:pattern}. If a regular expression pattern is not defined, the matched
|
||||
variable will be anything until the next slash. For example:
|
||||
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/products/{key}", ProductHandler)
|
||||
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
|
||||
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
|
||||
|
||||
The names are used to create a map of route variables which can be retrieved
|
||||
calling mux.Vars():
|
||||
|
||||
vars := mux.Vars(request)
|
||||
category := vars["category"]
|
||||
|
||||
And this is all you need to know about the basic usage. More advanced options
|
||||
are explained below.
|
||||
|
||||
Routes can also be restricted to a domain or subdomain. Just define a host
|
||||
pattern to be matched. They can also have variables:
|
||||
|
||||
r := mux.NewRouter()
|
||||
// Only matches if domain is "www.example.com".
|
||||
r.Host("www.example.com")
|
||||
// Matches a dynamic subdomain.
|
||||
r.Host("{subdomain:[a-z]+}.domain.com")
|
||||
|
||||
There are several other matchers that can be added. To match path prefixes:
|
||||
|
||||
r.PathPrefix("/products/")
|
||||
|
||||
...or HTTP methods:
|
||||
|
||||
r.Methods("GET", "POST")
|
||||
|
||||
...or URL schemes:
|
||||
|
||||
r.Schemes("https")
|
||||
|
||||
...or header values:
|
||||
|
||||
r.Headers("X-Requested-With", "XMLHttpRequest")
|
||||
|
||||
...or query values:
|
||||
|
||||
r.Queries("key", "value")
|
||||
|
||||
...or to use a custom matcher function:
|
||||
|
||||
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
|
||||
return r.ProtoMajor == 0
|
||||
})
|
||||
|
||||
...and finally, it is possible to combine several matchers in a single route:
|
||||
|
||||
r.HandleFunc("/products", ProductsHandler).
|
||||
Host("www.example.com").
|
||||
Methods("GET").
|
||||
Schemes("http")
|
||||
|
||||
Setting the same matching conditions again and again can be boring, so we have
|
||||
a way to group several routes that share the same requirements.
|
||||
We call it "subrouting".
|
||||
|
||||
For example, let's say we have several URLs that should only match when the
|
||||
host is `www.example.com`. Create a route for that host and get a "subrouter"
|
||||
from it:
|
||||
|
||||
r := mux.NewRouter()
|
||||
s := r.Host("www.example.com").Subrouter()
|
||||
|
||||
Then register routes in the subrouter:
|
||||
|
||||
s.HandleFunc("/products/", ProductsHandler)
|
||||
s.HandleFunc("/products/{key}", ProductHandler)
|
||||
s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
|
||||
|
||||
The three URL paths we registered above will only be tested if the domain is
|
||||
`www.example.com`, because the subrouter is tested first. This is not
|
||||
only convenient, but also optimizes request matching. You can create
|
||||
subrouters combining any attribute matchers accepted by a route.
|
||||
|
||||
Subrouters can be used to create domain or path "namespaces": you define
|
||||
subrouters in a central place and then parts of the app can register its
|
||||
paths relatively to a given subrouter.
|
||||
|
||||
There's one more thing about subroutes. When a subrouter has a path prefix,
|
||||
the inner routes use it as base for their paths:
|
||||
|
||||
r := mux.NewRouter()
|
||||
s := r.PathPrefix("/products").Subrouter()
|
||||
// "/products/"
|
||||
s.HandleFunc("/", ProductsHandler)
|
||||
// "/products/{key}/"
|
||||
s.HandleFunc("/{key}/", ProductHandler)
|
||||
// "/products/{key}/details"
|
||||
s.HandleFunc("/{key}/details", ProductDetailsHandler)
|
||||
|
||||
Now let's see how to build registered URLs.
|
||||
|
||||
Routes can be named. All routes that define a name can have their URLs built,
|
||||
or "reversed". We define a name calling Name() on a route. For example:
|
||||
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
|
||||
Name("article")
|
||||
|
||||
To build a URL, get the route and call the URL() method, passing a sequence of
|
||||
key/value pairs for the route variables. For the previous route, we would do:
|
||||
|
||||
url, err := r.Get("article").URL("category", "technology", "id", "42")
|
||||
|
||||
...and the result will be a url.URL with the following path:
|
||||
|
||||
"/articles/technology/42"
|
||||
|
||||
This also works for host variables:
|
||||
|
||||
r := mux.NewRouter()
|
||||
r.Host("{subdomain}.domain.com").
|
||||
Path("/articles/{category}/{id:[0-9]+}").
|
||||
HandlerFunc(ArticleHandler).
|
||||
Name("article")
|
||||
|
||||
// url.String() will be "http://news.domain.com/articles/technology/42"
|
||||
url, err := r.Get("article").URL("subdomain", "news",
|
||||
"category", "technology",
|
||||
"id", "42")
|
||||
|
||||
All variables defined in the route are required, and their values must
|
||||
conform to the corresponding patterns. These requirements guarantee that a
|
||||
generated URL will always match a registered route -- the only exception is
|
||||
for explicitly defined "build-only" routes which never match.
|
||||
|
||||
Regex support also exists for matching Headers within a route. For example, we could do:
|
||||
|
||||
r.HeadersRegexp("Content-Type", "application/(text|json)")
|
||||
|
||||
...and the route will match both requests with a Content-Type of `application/json` as well as
|
||||
`application/text`
|
||||
|
||||
There's also a way to build only the URL host or path for a route:
|
||||
use the methods URLHost() or URLPath() instead. For the previous route,
|
||||
we would do:
|
||||
|
||||
// "http://news.domain.com/"
|
||||
host, err := r.Get("article").URLHost("subdomain", "news")
|
||||
|
||||
// "/articles/technology/42"
|
||||
path, err := r.Get("article").URLPath("category", "technology", "id", "42")
|
||||
|
||||
And if you use subrouters, host and path defined separately can be built
|
||||
as well:
|
||||
|
||||
r := mux.NewRouter()
|
||||
s := r.Host("{subdomain}.domain.com").Subrouter()
|
||||
s.Path("/articles/{category}/{id:[0-9]+}").
|
||||
HandlerFunc(ArticleHandler).
|
||||
Name("article")
|
||||
|
||||
// "http://news.domain.com/articles/technology/42"
|
||||
url, err := r.Get("article").URL("subdomain", "news",
|
||||
"category", "technology",
|
||||
"id", "42")
|
||||
|
||||
## Full Example
|
||||
|
||||
Here's a complete, runnable example of a small mux based server:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func YourHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("Gorilla!\n"))
|
||||
}
|
||||
|
||||
func main() {
|
||||
r := mux.NewRouter()
|
||||
// Routes consist of a path and a handler function.
|
||||
r.HandleFunc("/", YourHandler)
|
||||
|
||||
// Bind to a port and pass our router in
|
||||
http.ListenAndServe(":8000", r)
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
BSD licensed. See the LICENSE file for details.
|
||||
|
@ -60,8 +60,8 @@ Routes can also be restricted to a domain or subdomain. Just define a host
|
||||
pattern to be matched. They can also have variables:
|
||||
|
||||
r := mux.NewRouter()
|
||||
// Only matches if domain is "www.domain.com".
|
||||
r.Host("www.domain.com")
|
||||
// Only matches if domain is "www.example.com".
|
||||
r.Host("www.example.com")
|
||||
// Matches a dynamic subdomain.
|
||||
r.Host("{subdomain:[a-z]+}.domain.com")
|
||||
|
||||
@ -94,7 +94,7 @@ There are several other matchers that can be added. To match path prefixes:
|
||||
...and finally, it is possible to combine several matchers in a single route:
|
||||
|
||||
r.HandleFunc("/products", ProductsHandler).
|
||||
Host("www.domain.com").
|
||||
Host("www.example.com").
|
||||
Methods("GET").
|
||||
Schemes("http")
|
||||
|
||||
@ -103,11 +103,11 @@ a way to group several routes that share the same requirements.
|
||||
We call it "subrouting".
|
||||
|
||||
For example, let's say we have several URLs that should only match when the
|
||||
host is "www.domain.com". Create a route for that host and get a "subrouter"
|
||||
host is "www.example.com". Create a route for that host and get a "subrouter"
|
||||
from it:
|
||||
|
||||
r := mux.NewRouter()
|
||||
s := r.Host("www.domain.com").Subrouter()
|
||||
s := r.Host("www.example.com").Subrouter()
|
||||
|
||||
Then register routes in the subrouter:
|
||||
|
||||
@ -116,7 +116,7 @@ Then register routes in the subrouter:
|
||||
s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
|
||||
|
||||
The three URL paths we registered above will only be tested if the domain is
|
||||
"www.domain.com", because the subrouter is tested first. This is not
|
||||
"www.example.com", because the subrouter is tested first. This is not
|
||||
only convenient, but also optimizes request matching. You can create
|
||||
subrouters combining any attribute matchers accepted by a route.
|
||||
|
||||
|
@ -312,6 +312,10 @@ func Vars(r *http.Request) map[string]string {
|
||||
}
|
||||
|
||||
// CurrentRoute returns the matched route for the current request, if any.
|
||||
// This only works when called inside the handler of the matched route
|
||||
// because the matched route is stored in the request context which is cleared
|
||||
// after the handler returns, unless the KeepContext option is set on the
|
||||
// Router.
|
||||
func CurrentRoute(r *http.Request) *Route {
|
||||
if rv := context.Get(r, routeKey); rv != nil {
|
||||
return rv.(*Route)
|
||||
|
@ -7,11 +7,24 @@ package mux
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/fsouza/go-dockerclient/external/github.com/gorilla/context"
|
||||
)
|
||||
|
||||
func (r *Route) GoString() string {
|
||||
matchers := make([]string, len(r.matchers))
|
||||
for i, m := range r.matchers {
|
||||
matchers[i] = fmt.Sprintf("%#v", m)
|
||||
}
|
||||
return fmt.Sprintf("&Route{matchers:[]matcher{%s}}", strings.Join(matchers, ", "))
|
||||
}
|
||||
|
||||
func (r *routeRegexp) GoString() string {
|
||||
return fmt.Sprintf("&routeRegexp{template: %q, matchHost: %t, matchQuery: %t, strictSlash: %t, regexp: regexp.MustCompile(%q), reverse: %q, varsN: %v, varsR: %v", r.template, r.matchHost, r.matchQuery, r.strictSlash, r.regexp.String(), r.reverse, r.varsN, r.varsR)
|
||||
}
|
||||
|
||||
type routeTest struct {
|
||||
title string // title of the test
|
||||
route *Route // the route being tested
|
||||
@ -108,6 +121,15 @@ func TestHost(t *testing.T) {
|
||||
path: "",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Host route with pattern, additional capturing group, match",
|
||||
route: new(Route).Host("aaa.{v1:[a-z]{2}(b|c)}.ccc"),
|
||||
request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
|
||||
vars: map[string]string{"v1": "bbb"},
|
||||
host: "aaa.bbb.ccc",
|
||||
path: "",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Host route with pattern, wrong host in request URL",
|
||||
route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"),
|
||||
@ -135,6 +157,33 @@ func TestHost(t *testing.T) {
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Host route with hyphenated name and pattern, match",
|
||||
route: new(Route).Host("aaa.{v-1:[a-z]{3}}.ccc"),
|
||||
request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
|
||||
vars: map[string]string{"v-1": "bbb"},
|
||||
host: "aaa.bbb.ccc",
|
||||
path: "",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Host route with hyphenated name and pattern, additional capturing group, match",
|
||||
route: new(Route).Host("aaa.{v-1:[a-z]{2}(b|c)}.ccc"),
|
||||
request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
|
||||
vars: map[string]string{"v-1": "bbb"},
|
||||
host: "aaa.bbb.ccc",
|
||||
path: "",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Host route with multiple hyphenated names and patterns, match",
|
||||
route: new(Route).Host("{v-1:[a-z]{3}}.{v-2:[a-z]{3}}.{v-3:[a-z]{3}}"),
|
||||
request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
|
||||
vars: map[string]string{"v-1": "aaa", "v-2": "bbb", "v-3": "ccc"},
|
||||
host: "aaa.bbb.ccc",
|
||||
path: "",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Path route with single pattern with pipe, match",
|
||||
route: new(Route).Path("/{category:a|b/c}"),
|
||||
@ -260,6 +309,42 @@ func TestPath(t *testing.T) {
|
||||
path: "/111/222/333",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Path route with multiple patterns with pipe, match",
|
||||
route: new(Route).Path("/{category:a|(b/c)}/{product}/{id:[0-9]+}"),
|
||||
request: newRequest("GET", "http://localhost/a/product_name/1"),
|
||||
vars: map[string]string{"category": "a", "product": "product_name", "id": "1"},
|
||||
host: "",
|
||||
path: "/a/product_name/1",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Path route with hyphenated name and pattern, match",
|
||||
route: new(Route).Path("/111/{v-1:[0-9]{3}}/333"),
|
||||
request: newRequest("GET", "http://localhost/111/222/333"),
|
||||
vars: map[string]string{"v-1": "222"},
|
||||
host: "",
|
||||
path: "/111/222/333",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Path route with multiple hyphenated names and patterns, match",
|
||||
route: new(Route).Path("/{v-1:[0-9]{3}}/{v-2:[0-9]{3}}/{v-3:[0-9]{3}}"),
|
||||
request: newRequest("GET", "http://localhost/111/222/333"),
|
||||
vars: map[string]string{"v-1": "111", "v-2": "222", "v-3": "333"},
|
||||
host: "",
|
||||
path: "/111/222/333",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Path route with multiple hyphenated names and patterns with pipe, match",
|
||||
route: new(Route).Path("/{product-category:a|(b/c)}/{product-name}/{product-id:[0-9]+}"),
|
||||
request: newRequest("GET", "http://localhost/a/product_name/1"),
|
||||
vars: map[string]string{"product-category": "a", "product-name": "product_name", "product-id": "1"},
|
||||
host: "",
|
||||
path: "/a/product_name/1",
|
||||
shouldMatch: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@ -597,6 +682,15 @@ func TestQueries(t *testing.T) {
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Queries route with regexp pattern with quantifier, additional capturing group",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}(a|b)}"),
|
||||
request: newRequest("GET", "http://localhost?foo=1a"),
|
||||
vars: map[string]string{"v1": "1a"},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with regexp pattern with quantifier, additional variable in query string, regexp does not match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
|
||||
@ -606,6 +700,42 @@ func TestQueries(t *testing.T) {
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Queries route with hyphenated name, match",
|
||||
route: new(Route).Queries("foo", "{v-1}"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar"),
|
||||
vars: map[string]string{"v-1": "bar"},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with multiple hyphenated names, match",
|
||||
route: new(Route).Queries("foo", "{v-1}", "baz", "{v-2}"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
|
||||
vars: map[string]string{"v-1": "bar", "v-2": "ding"},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with hyphenate name and pattern, match",
|
||||
route: new(Route).Queries("foo", "{v-1:[0-9]+}"),
|
||||
request: newRequest("GET", "http://localhost?foo=10"),
|
||||
vars: map[string]string{"v-1": "10"},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with hyphenated name and pattern with quantifier, additional capturing group",
|
||||
route: new(Route).Queries("foo", "{v-1:[0-9]{1}(a|b)}"),
|
||||
request: newRequest("GET", "http://localhost?foo=1a"),
|
||||
vars: map[string]string{"v-1": "1a"},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with empty value, should match",
|
||||
route: new(Route).Queries("foo", ""),
|
||||
@ -660,6 +790,15 @@ func TestQueries(t *testing.T) {
|
||||
path: "",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route, bad submatch",
|
||||
route: new(Route).Queries("foo", "bar", "baz", "ding"),
|
||||
request: newRequest("GET", "http://localhost?fffoo=bar&baz=dingggg"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
@ -545,7 +545,7 @@ func TestMatchedRouteName(t *testing.T) {
|
||||
router := NewRouter()
|
||||
route := router.NewRoute().Path("/products/").Name(routeName)
|
||||
|
||||
url := "http://www.domain.com/products/"
|
||||
url := "http://www.example.com/products/"
|
||||
request, _ := http.NewRequest("GET", url, nil)
|
||||
var rv RouteMatch
|
||||
ok := router.Match(request, &rv)
|
||||
@ -563,10 +563,10 @@ func TestMatchedRouteName(t *testing.T) {
|
||||
func TestSubRouting(t *testing.T) {
|
||||
// Example from docs.
|
||||
router := NewRouter()
|
||||
subrouter := router.NewRoute().Host("www.domain.com").Subrouter()
|
||||
subrouter := router.NewRoute().Host("www.example.com").Subrouter()
|
||||
route := subrouter.NewRoute().Path("/products/").Name("products")
|
||||
|
||||
url := "http://www.domain.com/products/"
|
||||
url := "http://www.example.com/products/"
|
||||
request, _ := http.NewRequest("GET", url, nil)
|
||||
var rv RouteMatch
|
||||
ok := router.Match(request, &rv)
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -72,13 +73,14 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||
tpl[idxs[i]:end])
|
||||
}
|
||||
// Build the regexp pattern.
|
||||
fmt.Fprintf(pattern, "%s(%s)", regexp.QuoteMeta(raw), patt)
|
||||
varIdx := i / 2
|
||||
fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(varIdx), patt)
|
||||
// Build the reverse template.
|
||||
fmt.Fprintf(reverse, "%s%%s", raw)
|
||||
|
||||
// Append variable name and compiled pattern.
|
||||
varsN[i/2] = name
|
||||
varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
|
||||
varsN[varIdx] = name
|
||||
varsR[varIdx], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -224,6 +226,11 @@ func braceIndices(s string) ([]int, error) {
|
||||
return idxs, nil
|
||||
}
|
||||
|
||||
// varGroupName builds a capturing group name for the indexed variable.
|
||||
func varGroupName(idx int) string {
|
||||
return "v" + strconv.Itoa(idx)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// routeRegexpGroup
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -241,8 +248,13 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
|
||||
if v.host != nil {
|
||||
hostVars := v.host.regexp.FindStringSubmatch(getHost(req))
|
||||
if hostVars != nil {
|
||||
for k, v := range v.host.varsN {
|
||||
m.Vars[v] = hostVars[k+1]
|
||||
subexpNames := v.host.regexp.SubexpNames()
|
||||
varName := 0
|
||||
for i, name := range subexpNames[1:] {
|
||||
if name != "" && name == varGroupName(varName) {
|
||||
m.Vars[v.host.varsN[varName]] = hostVars[i+1]
|
||||
varName++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -250,8 +262,13 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
|
||||
if v.path != nil {
|
||||
pathVars := v.path.regexp.FindStringSubmatch(req.URL.Path)
|
||||
if pathVars != nil {
|
||||
for k, v := range v.path.varsN {
|
||||
m.Vars[v] = pathVars[k+1]
|
||||
subexpNames := v.path.regexp.SubexpNames()
|
||||
varName := 0
|
||||
for i, name := range subexpNames[1:] {
|
||||
if name != "" && name == varGroupName(varName) {
|
||||
m.Vars[v.path.varsN[varName]] = pathVars[i+1]
|
||||
varName++
|
||||
}
|
||||
}
|
||||
// Check if we should redirect.
|
||||
if v.path.strictSlash {
|
||||
@ -273,8 +290,13 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
|
||||
for _, q := range v.queries {
|
||||
queryVars := q.regexp.FindStringSubmatch(q.getUrlQuery(req))
|
||||
if queryVars != nil {
|
||||
for k, v := range q.varsN {
|
||||
m.Vars[v] = queryVars[k+1]
|
||||
subexpNames := q.regexp.SubexpNames()
|
||||
varName := 0
|
||||
for i, name := range subexpNames[1:] {
|
||||
if name != "" && name == varGroupName(varName) {
|
||||
m.Vars[q.varsN[varName]] = queryVars[i+1]
|
||||
varName++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ func (r *Route) HeadersRegexp(pairs ...string) *Route {
|
||||
// For example:
|
||||
//
|
||||
// r := mux.NewRouter()
|
||||
// r.Host("www.domain.com")
|
||||
// r.Host("www.example.com")
|
||||
// r.Host("{subdomain}.domain.com")
|
||||
// r.Host("{subdomain:[a-z]+}.domain.com")
|
||||
//
|
||||
@ -414,7 +414,7 @@ func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
|
||||
// It will test the inner routes only if the parent route matched. For example:
|
||||
//
|
||||
// r := mux.NewRouter()
|
||||
// s := r.Host("www.domain.com").Subrouter()
|
||||
// s := r.Host("www.example.com").Subrouter()
|
||||
// s.HandleFunc("/products/", ProductsHandler)
|
||||
// s.HandleFunc("/products/{key}", ProductHandler)
|
||||
// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
|
||||
|
127
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/network.go
generated
vendored
Normal file
127
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/network.go
generated
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright 2015 go-dockerclient authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package docker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ErrNetworkAlreadyExists is the error returned by CreateNetwork when the
|
||||
// network already exists.
|
||||
var ErrNetworkAlreadyExists = errors.New("network already exists")
|
||||
|
||||
// Network represents a network.
|
||||
//
|
||||
// See https://goo.gl/FDkCdQ for more details.
|
||||
type Network struct {
|
||||
Name string `json:"name"`
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Endpoints []*Endpoint `json:"endpoints"`
|
||||
}
|
||||
|
||||
// Endpoint represents an endpoint.
|
||||
//
|
||||
// See https://goo.gl/FDkCdQ for more details.
|
||||
type Endpoint struct {
|
||||
Name string `json:"name"`
|
||||
ID string `json:"id"`
|
||||
Network string `json:"network"`
|
||||
}
|
||||
|
||||
// ListNetworks returns all networks.
|
||||
//
|
||||
// See https://goo.gl/4hCNtZ for more details.
|
||||
func (c *Client) ListNetworks() ([]Network, error) {
|
||||
body, _, err := c.do("GET", "/networks", doOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var networks []Network
|
||||
if err := json.Unmarshal(body, &networks); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return networks, nil
|
||||
}
|
||||
|
||||
// NetworkInfo returns information about a network by its ID.
|
||||
//
|
||||
// See https://goo.gl/4hCNtZ for more details.
|
||||
func (c *Client) NetworkInfo(id string) (*Network, error) {
|
||||
path := "/networks/" + id
|
||||
body, status, err := c.do("GET", path, doOptions{})
|
||||
if status == http.StatusNotFound {
|
||||
return nil, &NoSuchNetwork{ID: id}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var network Network
|
||||
if err := json.Unmarshal(body, &network); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &network, nil
|
||||
}
|
||||
|
||||
// CreateNetworkOptions specify parameters to the CreateNetwork function and
|
||||
// (for now) is the expected body of the "create network" http request message
|
||||
//
|
||||
// See https://goo.gl/FDkCdQ for more details.
|
||||
type CreateNetworkOptions struct {
|
||||
Name string `json:"name"`
|
||||
NetworkType string `json:"network_type"`
|
||||
Options map[string]interface{} `json:"options"`
|
||||
}
|
||||
|
||||
// CreateNetwork creates a new network, returning the network instance,
|
||||
// or an error in case of failure.
|
||||
//
|
||||
// See http://goo.gl/mErxNp for more details.
|
||||
func (c *Client) CreateNetwork(opts CreateNetworkOptions) (*Network, error) {
|
||||
body, status, err := c.do(
|
||||
"POST",
|
||||
"/networks",
|
||||
doOptions{
|
||||
data: opts,
|
||||
},
|
||||
)
|
||||
|
||||
if status == http.StatusConflict {
|
||||
return nil, ErrNetworkAlreadyExists
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
type createNetworkResponse struct {
|
||||
ID string
|
||||
}
|
||||
var (
|
||||
network Network
|
||||
resp createNetworkResponse
|
||||
)
|
||||
err = json.Unmarshal(body, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
network.Name = opts.Name
|
||||
network.ID = resp.ID
|
||||
network.Type = opts.NetworkType
|
||||
|
||||
return &network, nil
|
||||
}
|
||||
|
||||
// NoSuchNetwork is the error returned when a given network does not exist.
|
||||
type NoSuchNetwork struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (err *NoSuchNetwork) Error() string {
|
||||
return fmt.Sprintf("No such network: %s", err.ID)
|
||||
}
|
96
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/network_test.go
generated
vendored
Normal file
96
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/network_test.go
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright 2015 go-dockerclient authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package docker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListNetworks(t *testing.T) {
|
||||
jsonNetworks := `[
|
||||
{
|
||||
"ID": "8dfafdbc3a40",
|
||||
"Name": "blah",
|
||||
"Type": "bridge",
|
||||
"Endpoints":[{"ID": "918c11c8288a", "Name": "dsafdsaf", "Network": "8dfafdbc3a40"}]
|
||||
},
|
||||
{
|
||||
"ID": "9fb1e39c",
|
||||
"Name": "foo",
|
||||
"Type": "bridge",
|
||||
"Endpoints":[{"ID": "c080be979dda", "Name": "lllll2222", "Network": "9fb1e39c"}]
|
||||
}
|
||||
]`
|
||||
var expected []Network
|
||||
err := json.Unmarshal([]byte(jsonNetworks), &expected)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
client := newTestClient(&FakeRoundTripper{message: jsonNetworks, status: http.StatusOK})
|
||||
containers, err := client.ListNetworks()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(containers, expected) {
|
||||
t.Errorf("ListNetworks: Expected %#v. Got %#v.", expected, containers)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkInfo(t *testing.T) {
|
||||
jsonNetwork := `{
|
||||
"ID": "8dfafdbc3a40",
|
||||
"Name": "blah",
|
||||
"Type": "bridge",
|
||||
"Endpoints":[{"ID": "918c11c8288a", "Name": "dsafdsaf", "Network": "8dfafdbc3a40"}]
|
||||
}`
|
||||
var expected Network
|
||||
err := json.Unmarshal([]byte(jsonNetwork), &expected)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fakeRT := &FakeRoundTripper{message: jsonNetwork, status: http.StatusOK}
|
||||
client := newTestClient(fakeRT)
|
||||
id := "8dfafdbc3a40"
|
||||
network, err := client.NetworkInfo(id)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(*network, expected) {
|
||||
t.Errorf("NetworkInfo(%q): Expected %#v. Got %#v.", id, expected, network)
|
||||
}
|
||||
expectedURL, _ := url.Parse(client.getURL("/networks/8dfafdbc3a40"))
|
||||
if gotPath := fakeRT.requests[0].URL.Path; gotPath != expectedURL.Path {
|
||||
t.Errorf("NetworkInfo(%q): Wrong path in request. Want %q. Got %q.", id, expectedURL.Path, gotPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkCreate(t *testing.T) {
|
||||
jsonID := `{"ID": "8dfafdbc3a40"}`
|
||||
jsonNetwork := `{
|
||||
"ID": "8dfafdbc3a40",
|
||||
"Name": "foobar",
|
||||
"Type": "bridge"
|
||||
}`
|
||||
var expected Network
|
||||
err := json.Unmarshal([]byte(jsonNetwork), &expected)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
client := newTestClient(&FakeRoundTripper{message: jsonID, status: http.StatusOK})
|
||||
opts := CreateNetworkOptions{"foobar", "bridge", nil}
|
||||
network, err := client.CreateNetwork(opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(*network, expected) {
|
||||
t.Errorf("CreateNetwork: Expected %#v. Got %#v.", expected, network)
|
||||
}
|
||||
}
|
79
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/server.go
generated
vendored
79
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/server.go
generated
vendored
@ -43,6 +43,8 @@ type DockerServer struct {
|
||||
images []docker.Image
|
||||
iMut sync.RWMutex
|
||||
imgIDs map[string]string
|
||||
networks []*docker.Network
|
||||
netMut sync.RWMutex
|
||||
listener net.Listener
|
||||
mux *mux.Router
|
||||
hook func(*http.Request)
|
||||
@ -124,6 +126,9 @@ func (s *DockerServer) buildMuxer() {
|
||||
s.mux.Path("/_ping").Methods("GET").HandlerFunc(s.handlerWrapper(s.pingDocker))
|
||||
s.mux.Path("/images/load").Methods("POST").HandlerFunc(s.handlerWrapper(s.loadImage))
|
||||
s.mux.Path("/images/{id:.*}/get").Methods("GET").HandlerFunc(s.handlerWrapper(s.getImage))
|
||||
s.mux.Path("/networks").Methods("GET").HandlerFunc(s.handlerWrapper(s.listNetworks))
|
||||
s.mux.Path("/networks/{id:.*}").Methods("GET").HandlerFunc(s.handlerWrapper(s.networkInfo))
|
||||
s.mux.Path("/networks").Methods("POST").HandlerFunc(s.handlerWrapper(s.createNetwork))
|
||||
}
|
||||
|
||||
// SetHook changes the hook function used by the server.
|
||||
@ -981,3 +986,77 @@ func (s *DockerServer) getExec(id string) (*docker.ExecInspect, error) {
|
||||
}
|
||||
return nil, errors.New("exec not found")
|
||||
}
|
||||
|
||||
func (s *DockerServer) findNetwork(idOrName string) (*docker.Network, int, error) {
|
||||
s.netMut.RLock()
|
||||
defer s.netMut.RUnlock()
|
||||
for i, network := range s.networks {
|
||||
if network.ID == idOrName || network.Name == idOrName {
|
||||
return network, i, nil
|
||||
}
|
||||
}
|
||||
return nil, -1, errors.New("No such network")
|
||||
}
|
||||
|
||||
func (s *DockerServer) listNetworks(w http.ResponseWriter, r *http.Request) {
|
||||
s.netMut.RLock()
|
||||
result := make([]docker.Network, 0, len(s.networks))
|
||||
for _, network := range s.networks {
|
||||
result = append(result, *network)
|
||||
}
|
||||
s.netMut.RUnlock()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(result)
|
||||
}
|
||||
|
||||
func (s *DockerServer) networkInfo(w http.ResponseWriter, r *http.Request) {
|
||||
id := mux.Vars(r)["id"]
|
||||
network, _, err := s.findNetwork(id)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(network)
|
||||
}
|
||||
|
||||
// isValidName validates configuration objects supported by libnetwork
|
||||
func isValidName(name string) bool {
|
||||
if name == "" || strings.Contains(name, ".") {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *DockerServer) createNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
var config *docker.CreateNetworkOptions
|
||||
defer r.Body.Close()
|
||||
err := json.NewDecoder(r.Body).Decode(&config)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if !isValidName(config.Name) {
|
||||
http.Error(w, "Invalid network name", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if n, _, _ := s.findNetwork(config.Name); n != nil {
|
||||
http.Error(w, "network already exists", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
generatedID := s.generateID()
|
||||
network := docker.Network{
|
||||
Name: config.Name,
|
||||
ID: generatedID,
|
||||
Type: config.NetworkType,
|
||||
}
|
||||
s.netMut.Lock()
|
||||
s.networks = append(s.networks, &network)
|
||||
s.netMut.Unlock()
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
var c = struct{ ID string }{ID: network.ID}
|
||||
json.NewEncoder(w).Encode(c)
|
||||
}
|
||||
|
103
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/server_test.go
generated
vendored
103
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/server_test.go
generated
vendored
@ -1679,3 +1679,106 @@ func TestStatsContainerStream(t *testing.T) {
|
||||
t.Errorf("StatsContainer: wrong value. Want %#v. Got %#v.", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func addNetworks(server *DockerServer, n int) {
|
||||
server.netMut.Lock()
|
||||
defer server.netMut.Unlock()
|
||||
for i := 0; i < n; i++ {
|
||||
netid := fmt.Sprintf("%x", rand.Int()%10000)
|
||||
network := docker.Network{
|
||||
Name: netid,
|
||||
ID: fmt.Sprintf("%x", rand.Int()%10000),
|
||||
Type: "bridge",
|
||||
Endpoints: []*docker.Endpoint{
|
||||
&docker.Endpoint{
|
||||
Name: "blah",
|
||||
ID: fmt.Sprintf("%x", rand.Int()%10000),
|
||||
Network: netid,
|
||||
},
|
||||
},
|
||||
}
|
||||
server.networks = append(server.networks, &network)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListNetworks(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
addNetworks(&server, 2)
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/networks", nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Errorf("ListNetworks: wrong status. Want %d. Got %d.", http.StatusOK, recorder.Code)
|
||||
}
|
||||
expected := make([]docker.Network, 2)
|
||||
for i, network := range server.networks {
|
||||
expected[i] = docker.Network{
|
||||
ID: network.ID,
|
||||
Name: network.Name,
|
||||
Type: network.Type,
|
||||
Endpoints: network.Endpoints,
|
||||
}
|
||||
}
|
||||
var got []docker.Network
|
||||
err := json.NewDecoder(recorder.Body).Decode(&got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, expected) {
|
||||
t.Errorf("ListNetworks. Want %#v. Got %#v.", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
type createNetworkResponse struct {
|
||||
ID string `json:"ID"`
|
||||
}
|
||||
|
||||
func TestCreateNetwork(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
netid := fmt.Sprintf("%x", rand.Int()%10000)
|
||||
netname := fmt.Sprintf("%x", rand.Int()%10000)
|
||||
body := fmt.Sprintf(`{"ID": "%s", "Name": "%s", "Type": "bridge" }`, netid, netname)
|
||||
request, _ := http.NewRequest("POST", "/networks", strings.NewReader(body))
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusCreated {
|
||||
t.Errorf("CreateNetwork: wrong status. Want %d. Got %d.", http.StatusCreated, recorder.Code)
|
||||
}
|
||||
|
||||
var returned createNetworkResponse
|
||||
err := json.NewDecoder(recorder.Body).Decode(&returned)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stored := server.networks[0]
|
||||
if returned.ID != stored.ID {
|
||||
t.Errorf("CreateNetwork: ID mismatch. Stored: %q. Returned: %q.", stored.ID, returned)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateNetworkInvalidBody(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("POST", "/networks", strings.NewReader("whaaaaaat---"))
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusBadRequest {
|
||||
t.Errorf("CreateNetwork: wrong status. Want %d. Got %d.", http.StatusBadRequest, recorder.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateNetworkDuplicateName(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
server.buildMuxer()
|
||||
addNetworks(&server, 1)
|
||||
server.networks[0].Name = "mynetwork"
|
||||
recorder := httptest.NewRecorder()
|
||||
body := fmt.Sprintf(`{"ID": "%s", "Name": "mynetwork", "Type": "bridge" }`, fmt.Sprintf("%x", rand.Int()%10000))
|
||||
request, _ := http.NewRequest("POST", "/networks", strings.NewReader(body))
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusForbidden {
|
||||
t.Errorf("CreateNetwork: wrong status. Want %d. Got %d.", http.StatusForbidden, recorder.Code)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user