diff --git a/Dockerfile b/Dockerfile
index 109e4268..66504959 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,8 @@
-FROM golang:1.5.1
+FROM golang:1.6
-# Copy latest docker client(s)
-COPY ./docker/docker-1.9.1 /bin/docker-1.9.1
+# Copy latest docker client inside the container
+COPY ./docker/docker-1.10.2 /bin/docker-1.10.2
+# and make it executable
RUN chmod +x /bin/docker-*
# Copy Go code and install applications
diff --git a/docker/docker-1.9.1 b/docker/docker-1.10.2
similarity index 68%
rename from docker/docker-1.9.1
rename to docker/docker-1.10.2
index 8090020c..1e1895f9 100644
Binary files a/docker/docker-1.9.1 and b/docker/docker-1.10.2 differ
diff --git a/go/src/github.com/Sirupsen/logrus/.gitignore b/go/src/github.com/Sirupsen/logrus/.gitignore
deleted file mode 100644
index 66be63a0..00000000
--- a/go/src/github.com/Sirupsen/logrus/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-logrus
diff --git a/go/src/github.com/Sirupsen/logrus/.travis.yml b/go/src/github.com/Sirupsen/logrus/.travis.yml
deleted file mode 100644
index ec641142..00000000
--- a/go/src/github.com/Sirupsen/logrus/.travis.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-language: go
-go:
- - 1.3
- - 1.4
- - tip
-install:
- - go get -t ./...
diff --git a/go/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go b/go/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go
deleted file mode 100644
index d20a0f54..00000000
--- a/go/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package logrus_bugsnag
-
-import (
- "errors"
-
- "github.com/Sirupsen/logrus"
- "github.com/bugsnag/bugsnag-go"
-)
-
-type bugsnagHook struct{}
-
-// ErrBugsnagUnconfigured is returned if NewBugsnagHook is called before
-// bugsnag.Configure. Bugsnag must be configured before the hook.
-var ErrBugsnagUnconfigured = errors.New("bugsnag must be configured before installing this logrus hook")
-
-// ErrBugsnagSendFailed indicates that the hook failed to submit an error to
-// bugsnag. The error was successfully generated, but `bugsnag.Notify()`
-// failed.
-type ErrBugsnagSendFailed struct {
- err error
-}
-
-func (e ErrBugsnagSendFailed) Error() string {
- return "failed to send error to Bugsnag: " + e.err.Error()
-}
-
-// NewBugsnagHook initializes a logrus hook which sends exceptions to an
-// exception-tracking service compatible with the Bugsnag API. Before using
-// this hook, you must call bugsnag.Configure(). The returned object should be
-// registered with a log via `AddHook()`
-//
-// Entries that trigger an Error, Fatal or Panic should now include an "error"
-// field to send to Bugsnag.
-func NewBugsnagHook() (*bugsnagHook, error) {
- if bugsnag.Config.APIKey == "" {
- return nil, ErrBugsnagUnconfigured
- }
- return &bugsnagHook{}, nil
-}
-
-// Fire forwards an error to Bugsnag. Given a logrus.Entry, it extracts the
-// "error" field (or the Message if the error isn't present) and sends it off.
-func (hook *bugsnagHook) Fire(entry *logrus.Entry) error {
- var notifyErr error
- err, ok := entry.Data["error"].(error)
- if ok {
- notifyErr = err
- } else {
- notifyErr = errors.New(entry.Message)
- }
-
- bugsnagErr := bugsnag.Notify(notifyErr)
- if bugsnagErr != nil {
- return ErrBugsnagSendFailed{bugsnagErr}
- }
-
- return nil
-}
-
-// Levels enumerates the log levels on which the error should be forwarded to
-// bugsnag: everything at or above the "Error" level.
-func (hook *bugsnagHook) Levels() []logrus.Level {
- return []logrus.Level{
- logrus.ErrorLevel,
- logrus.FatalLevel,
- logrus.PanicLevel,
- }
-}
diff --git a/go/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag_test.go b/go/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag_test.go
deleted file mode 100644
index e9ea298d..00000000
--- a/go/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag_test.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package logrus_bugsnag
-
-import (
- "encoding/json"
- "errors"
- "io/ioutil"
- "net/http"
- "net/http/httptest"
- "testing"
- "time"
-
- "github.com/Sirupsen/logrus"
- "github.com/bugsnag/bugsnag-go"
-)
-
-type notice struct {
- Events []struct {
- Exceptions []struct {
- Message string `json:"message"`
- } `json:"exceptions"`
- } `json:"events"`
-}
-
-func TestNoticeReceived(t *testing.T) {
- msg := make(chan string, 1)
- expectedMsg := "foo"
-
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- var notice notice
- data, _ := ioutil.ReadAll(r.Body)
- if err := json.Unmarshal(data, ¬ice); err != nil {
- t.Error(err)
- }
- _ = r.Body.Close()
-
- msg <- notice.Events[0].Exceptions[0].Message
- }))
- defer ts.Close()
-
- hook := &bugsnagHook{}
-
- bugsnag.Configure(bugsnag.Configuration{
- Endpoint: ts.URL,
- ReleaseStage: "production",
- APIKey: "12345678901234567890123456789012",
- Synchronous: true,
- })
-
- log := logrus.New()
- log.Hooks.Add(hook)
-
- log.WithFields(logrus.Fields{
- "error": errors.New(expectedMsg),
- }).Error("Bugsnag will not see this string")
-
- select {
- case received := <-msg:
- if received != expectedMsg {
- t.Errorf("Unexpected message received: %s", received)
- }
- case <-time.After(time.Second):
- t.Error("Timed out; no notice received by Bugsnag API")
- }
-}
diff --git a/go/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md b/go/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md
deleted file mode 100644
index ae61e922..00000000
--- a/go/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Papertrail Hook for Logrus
-
-[Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts).
-
-In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible.
-
-## Usage
-
-You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`.
-
-For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs.
-
-```go
-import (
- "log/syslog"
- "github.com/Sirupsen/logrus"
- "github.com/Sirupsen/logrus/hooks/papertrail"
-)
-
-func main() {
- log := logrus.New()
- hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME)
-
- if err == nil {
- log.Hooks.Add(hook)
- }
-}
-```
diff --git a/go/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go b/go/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
deleted file mode 100644
index c0f10c1b..00000000
--- a/go/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package logrus_papertrail
-
-import (
- "fmt"
- "net"
- "os"
- "time"
-
- "github.com/Sirupsen/logrus"
-)
-
-const (
- format = "Jan 2 15:04:05"
-)
-
-// PapertrailHook to send logs to a logging service compatible with the Papertrail API.
-type PapertrailHook struct {
- Host string
- Port int
- AppName string
- UDPConn net.Conn
-}
-
-// NewPapertrailHook creates a hook to be added to an instance of logger.
-func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) {
- conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port))
- return &PapertrailHook{host, port, appName, conn}, err
-}
-
-// Fire is called when a log event is fired.
-func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
- date := time.Now().Format(format)
- msg, _ := entry.String()
- payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg)
-
- bytesWritten, err := hook.UDPConn.Write([]byte(payload))
- if err != nil {
- fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err)
- return err
- }
-
- return nil
-}
-
-// Levels returns the available logging levels.
-func (hook *PapertrailHook) Levels() []logrus.Level {
- return []logrus.Level{
- logrus.PanicLevel,
- logrus.FatalLevel,
- logrus.ErrorLevel,
- logrus.WarnLevel,
- logrus.InfoLevel,
- logrus.DebugLevel,
- }
-}
diff --git a/go/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go b/go/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go
deleted file mode 100644
index 96318d00..00000000
--- a/go/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package logrus_papertrail
-
-import (
- "fmt"
- "testing"
-
- "github.com/Sirupsen/logrus"
- "github.com/stvp/go-udp-testing"
-)
-
-func TestWritingToUDP(t *testing.T) {
- port := 16661
- udp.SetAddr(fmt.Sprintf(":%d", port))
-
- hook, err := NewPapertrailHook("localhost", port, "test")
- if err != nil {
- t.Errorf("Unable to connect to local UDP server.")
- }
-
- log := logrus.New()
- log.Hooks.Add(hook)
-
- udp.ShouldReceive(t, "foo", func() {
- log.Info("foo")
- })
-}
diff --git a/go/src/github.com/samalba/dockerclient/.gitignore b/go/src/github.com/samalba/dockerclient/.gitignore
deleted file mode 100755
index 00268614..00000000
--- a/go/src/github.com/samalba/dockerclient/.gitignore
+++ /dev/null
@@ -1,22 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
diff --git a/go/src/goproxy/main.go b/go/src/goproxy/main.go
index 7b11e026..6b635484 100644
--- a/go/src/goproxy/main.go
+++ b/go/src/goproxy/main.go
@@ -27,18 +27,21 @@ import (
// instance of DockerClient allowing for making calls to the docker daemon
// remote API
var dockerClient *dockerclient.DockerClient
-// version of the docker daemon which is exposing the remote API
+
+// version of the docker daemon goproxy is connected to
var dockerDaemonVersion string
+//
type CPUStats struct {
TotalUsage uint64
SystemUsage uint64
}
-// previousCPUStats is a map containing the previous CPU stats we got from the
+// previousCPUStats is a map containing the previous CPU stats we got from the
// docker daemon through the docker remote API
var previousCPUStats map[string]*CPUStats = make(map[string]*CPUStats)
+// main function of goproxy
func main() {
// goproxy is executed as a short lived process to send a request to the
@@ -59,6 +62,8 @@ func main() {
return
}
+ logrus.Println("[goproxy] starting dockercraft goproxy daemon...")
+
// init docker client object
var err error
dockerClient, err = dockerclient.NewDockerClient("unix:///var/run/docker.sock", nil)
@@ -89,98 +94,133 @@ func main() {
// eventCallback receives and handles the docker events
func eventCallback(event *dockerclient.Event, ec chan error, args ...interface{}) {
- logrus.Debugln("--\n%+v", *event)
-
- id := event.Id
-
- switch event.Status {
- case "create":
- logrus.Debugln("create event")
-
- repo, tag := splitRepoAndTag(event.From)
- containerName := ""
- containerInfo, err := dockerClient.InspectContainer(id)
- if err != nil {
- logrus.Print("InspectContainer error:", err.Error())
- } else {
- containerName = containerInfo.Name
- }
-
- data := url.Values{
- "action": {"createContainer"},
- "id": {id},
- "name": {containerName},
- "imageRepo": {repo},
- "imageTag": {tag}}
-
- CuberiteServerRequest(data)
-
- case "start":
- logrus.Debugln("start event")
-
- repo, tag := splitRepoAndTag(event.From)
- containerName := ""
- containerInfo, err := dockerClient.InspectContainer(id)
- if err != nil {
- logrus.Print("InspectContainer error:", err.Error())
- } else {
- containerName = containerInfo.Name
- }
-
- data := url.Values{
- "action": {"startContainer"},
- "id": {id},
- "name": {containerName},
- "imageRepo": {repo},
- "imageTag": {tag}}
-
- // Monitor stats
- dockerClient.StartMonitorStats(id, statCallback, nil)
- CuberiteServerRequest(data)
-
- case "stop":
- // die event is enough
- // http://docs.docker.com/reference/api/docker_remote_api/#docker-events
-
- case "restart":
- // start event is enough
- // http://docs.docker.com/reference/api/docker_remote_api/#docker-events
-
- case "kill":
- // die event is enough
- // http://docs.docker.com/reference/api/docker_remote_api/#docker-events
-
- case "die":
- logrus.Debugln("die event")
-
- // same as stop event
- repo, tag := splitRepoAndTag(event.From)
- containerName := ""
- containerInfo, err := dockerClient.InspectContainer(id)
- if err != nil {
- logrus.Print("InspectContainer error:", err.Error())
- } else {
- containerName = containerInfo.Name
+ // logrus.Println("[goproxy] [event] ----- event -----")
+ // logrus.Println("[goproxy] [event] | type :", event.Type)
+ // logrus.Println("[goproxy] [event] | action:", event.Action)
+
+ // handle different kind of events
+ switch event.Type {
+ case "container":
+ // TODO: gdevillele: maybe check for "event.Action" instead of
+ // "event.Status" for event of type "container"
+ switch event.Status {
+ case "create":
+ // logrus.Println("[goproxy] [event received] create")
+ // get container ID
+ containerId := event.ID
+ repo, tag := splitRepoAndTag(event.From)
+ containerName := ""
+ containerInfo, err := dockerClient.InspectContainer(containerId)
+ if err != nil {
+ logrus.Print("InspectContainer error:", err.Error())
+ } else {
+ containerName = containerInfo.Name
+ }
+ data := url.Values{
+ "action": {"createContainer"},
+ "id": {containerId},
+ "name": {containerName},
+ "imageRepo": {repo},
+ "imageTag": {tag}}
+ CuberiteServerRequest(data)
+ case "start":
+ // logrus.Println("[goproxy] [event received] start")
+ // get container ID
+ containerId := event.ID
+ repo, tag := splitRepoAndTag(event.From)
+ containerName := ""
+ containerInfo, err := dockerClient.InspectContainer(containerId)
+ if err != nil {
+ logrus.Print("InspectContainer error:", err.Error())
+ } else {
+ containerName = containerInfo.Name
+ }
+ data := url.Values{
+ "action": {"startContainer"},
+ "id": {containerId},
+ "name": {containerName},
+ "imageRepo": {repo},
+ "imageTag": {tag}}
+ // Monitor stats
+ dockerClient.StartMonitorStats(containerId, statCallback, nil)
+ CuberiteServerRequest(data)
+ case "stop":
+ // die event is enough
+ // http://docs.docker.com/reference/api/docker_remote_api/#docker-events
+ case "restart":
+ // start event is enough
+ // http://docs.docker.com/reference/api/docker_remote_api/#docker-events
+ case "kill":
+ // die event is enough
+ // http://docs.docker.com/reference/api/docker_remote_api/#docker-events
+ case "die":
+ // logrus.Println("[goproxy] [event received] die")
+ // same as stop event
+ // get container ID
+ containerId := event.ID
+ repo, tag := splitRepoAndTag(event.From)
+ containerName := ""
+ containerInfo, err := dockerClient.InspectContainer(containerId)
+ if err != nil {
+ logrus.Print("InspectContainer error:", err.Error())
+ } else {
+ containerName = containerInfo.Name
+ }
+ data := url.Values{
+ "action": {"stopContainer"},
+ "id": {containerId},
+ "name": {containerName},
+ "imageRepo": {repo},
+ "imageTag": {tag}}
+ CuberiteServerRequest(data)
+ case "destroy":
+ // logrus.Println("[goproxy] [event received] destroy")
+ // get container ID
+ containerId := event.ID
+ data := url.Values{
+ "action": {"destroyContainer"},
+ "id": {containerId},
+ }
+ CuberiteServerRequest(data)
}
+ // TODO: gdevillele: disable network events for now
+ case "network":
+ switch event.Action {
+ case "connect":
+ // a container has been connected to a network
+
+ // id of the network
+ networkID := event.Actor.ID
+ // name of network
+ networkName := event.Actor.Attributes["name"]
+ // type of network
+ networkType := event.Actor.Attributes["type"]
+ // id of container affected
+ containerID := event.Actor.Attributes["container"]
+
+ // TODO: gdevillele: clean this
+ if networkName == "bridge" || networkName == "none" || networkName == "host" {
+ // those are default network values
+ // we do nothing for now
+ return
+ }
- data := url.Values{
- "action": {"stopContainer"},
- "id": {id},
- "name": {containerName},
- "imageRepo": {repo},
- "imageTag": {tag}}
-
- CuberiteServerRequest(data)
-
- case "destroy":
- logrus.Debugln("destroy event")
+ logrus.Println("[goproxy] [event] ----- custom network connect -----")
+ logrus.Println("[goproxy] [event] | networkID:", networkID)
+ logrus.Println("[goproxy] [event] | networkName:", networkName)
+ logrus.Println("[goproxy] [event] | networkType:", networkType)
+ logrus.Println("[goproxy] [event] | containerID:", containerID)
- data := url.Values{
- "action": {"destroyContainer"},
- "id": {id},
+ // send a HTTP request to the Cuberite server
+ data := url.Values{
+ "action": {"network_connect"},
+ "networkId": {networkID},
+ "networkName": {networkName},
+ "networkType": {networkType},
+ "containerId": {containerID},
+ }
+ CuberiteServerRequest(data)
}
-
- CuberiteServerRequest(data)
}
}
@@ -188,6 +228,9 @@ func eventCallback(event *dockerclient.Event, ec chan error, args ...interface{}
// the cuberite server
func statCallback(id string, stat *dockerclient.Stats, ec chan error, args ...interface{}) {
+ // TODO: gdevillele: re-activate stats later
+ return
+
// logrus.Debugln("STATS", id, stat)
// logrus.Debugln("---")
// logrus.Debugln("cpu :", float64(stat.CpuStats.CpuUsage.TotalUsage)/float64(stat.CpuStats.SystemUsage))
@@ -243,32 +286,28 @@ func execCmd(w http.ResponseWriter, r *http.Request) {
// listContainers handles and reply to http requests having the path "/containers"
func listContainers(w http.ResponseWriter, r *http.Request) {
- // answer right away to avoid dead locks in LUA
+ // answer right away to avoid deadlocks in LUA
io.WriteString(w, "OK")
go func() {
containers, err := dockerClient.ListContainers(true, false, "")
-
if err != nil {
logrus.Println(err.Error())
return
}
images, err := dockerClient.ListImages(true)
-
if err != nil {
logrus.Println(err.Error())
return
}
for i := 0; i < len(containers); i++ {
-
id := containers[i].Id
info, _ := dockerClient.InspectContainer(id)
name := info.Name[1:]
imageRepo := ""
imageTag := ""
-
for _, image := range images {
if image.Id == info.Image {
if len(image.RepoTags) > 0 {
diff --git a/go/src/goproxy/vendor/github.com/Sirupsen/logrus/.travis.yml b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/.travis.yml
new file mode 100644
index 00000000..ff23150d
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+go:
+ - 1.3
+ - 1.4
+ - 1.5
+ - tip
+install:
+ - go get -t ./...
+script: GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./...
diff --git a/go/src/github.com/Sirupsen/logrus/CHANGELOG.md b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/CHANGELOG.md
similarity index 79%
rename from go/src/github.com/Sirupsen/logrus/CHANGELOG.md
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/CHANGELOG.md
index 53616dbc..9e9e6009 100644
--- a/go/src/github.com/Sirupsen/logrus/CHANGELOG.md
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/CHANGELOG.md
@@ -1,8 +1,14 @@
-# 0.9.0 (Unreleased)
+# 0.9.0
* logrus/text_formatter: don't emit empty msg
* logrus/hooks/airbrake: move out of main repository
* logrus/hooks/sentry: move out of main repository
+* logrus/hooks/papertrail: move out of main repository
+* logrus/hooks/bugsnag: move out of main repository
+* logrus/core: run tests with `-race`
+* logrus/core: detect TTY based on `stderr`
+* logrus/core: support `WithError` on logger
+* logrus/core: Solaris support
# 0.8.7
diff --git a/go/src/github.com/Sirupsen/logrus/LICENSE b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/LICENSE
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/LICENSE
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/LICENSE
diff --git a/go/src/github.com/Sirupsen/logrus/README.md b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/README.md
similarity index 84%
rename from go/src/github.com/Sirupsen/logrus/README.md
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/README.md
index 3e526c1b..d3a1d4cf 100644
--- a/go/src/github.com/Sirupsen/logrus/README.md
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/README.md
@@ -1,4 +1,4 @@
-# Logrus
[](https://travis-ci.org/Sirupsen/logrus) [][godoc]
+# Logrus
[](https://travis-ci.org/Sirupsen/logrus) [](https://godoc.org/github.com/Sirupsen/logrus)
Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
@@ -202,9 +202,9 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
| ----- | ----------- |
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
-| [Papertrail](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go) | Send errors to the Papertrail hosted logging service via UDP. |
+| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
-| [BugSnag](https://github.com/Sirupsen/logrus/blob/master/hooks/bugsnag/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
+| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
@@ -218,6 +218,12 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
+| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
+| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
+| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
+| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
+| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
+| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
#### Level logging
@@ -298,12 +304,13 @@ The built-in logging formatters are:
* `logrus/formatters/logstash.LogstashFormatter`. Logs fields as [Logstash](http://logstash.net) Events.
```go
- logrus.SetFormatter(&logstash.LogstashFormatter{Type: “application_name"})
+ logrus.SetFormatter(&logstash.LogstashFormatter{Type: "application_name"})
```
Third party logging formatters:
-* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
+* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
+* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
You can define your formatter by implementing the `Formatter` interface,
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
@@ -352,5 +359,27 @@ Log rotation is not provided with Logrus. Log rotation should be done by an
external program (like `logrotate(8)`) that can compress and delete old log
entries. It should not be a feature of the application-level logger.
+#### Tools
-[godoc]: https://godoc.org/github.com/Sirupsen/logrus
+| Tool | Description |
+| ---- | ----------- |
+|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
+
+#### Testing
+
+Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
+
+* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
+* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
+
+```go
+logger, hook := NewNullLogger()
+logger.Error("Hello error")
+
+assert.Equal(1, len(hook.Entries))
+assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+assert.Equal("Hello error", hook.LastEntry().Message)
+
+hook.Reset()
+assert.Nil(hook.LastEntry())
+```
diff --git a/go/src/github.com/Sirupsen/logrus/doc.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/doc.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/doc.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/doc.go
diff --git a/go/src/github.com/Sirupsen/logrus/entry.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/entry.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/entry.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/entry.go
diff --git a/go/src/github.com/Sirupsen/logrus/entry_test.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/entry_test.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/entry_test.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/entry_test.go
diff --git a/go/src/github.com/Sirupsen/logrus/examples/basic/basic.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/examples/basic/basic.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
diff --git a/go/src/github.com/Sirupsen/logrus/examples/hook/hook.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/examples/hook/hook.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
diff --git a/go/src/github.com/Sirupsen/logrus/exported.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/exported.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/exported.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/exported.go
diff --git a/go/src/github.com/Sirupsen/logrus/formatter.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/formatter.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/formatter.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/formatter.go
diff --git a/go/src/github.com/Sirupsen/logrus/formatter_bench_test.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/formatter_bench_test.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
diff --git a/go/src/github.com/Sirupsen/logrus/formatters/logstash/logstash.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
similarity index 68%
rename from go/src/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
index 8ea93ddf..aad646ab 100644
--- a/go/src/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
@@ -17,38 +17,43 @@ type LogstashFormatter struct {
}
func (f *LogstashFormatter) Format(entry *logrus.Entry) ([]byte, error) {
- entry.Data["@version"] = 1
+ fields := make(logrus.Fields)
+ for k, v := range entry.Data {
+ fields[k] = v
+ }
+
+ fields["@version"] = 1
if f.TimestampFormat == "" {
f.TimestampFormat = logrus.DefaultTimestampFormat
}
- entry.Data["@timestamp"] = entry.Time.Format(f.TimestampFormat)
+ fields["@timestamp"] = entry.Time.Format(f.TimestampFormat)
// set message field
v, ok := entry.Data["message"]
if ok {
- entry.Data["fields.message"] = v
+ fields["fields.message"] = v
}
- entry.Data["message"] = entry.Message
+ fields["message"] = entry.Message
// set level field
v, ok = entry.Data["level"]
if ok {
- entry.Data["fields.level"] = v
+ fields["fields.level"] = v
}
- entry.Data["level"] = entry.Level.String()
+ fields["level"] = entry.Level.String()
// set type field
if f.Type != "" {
v, ok = entry.Data["type"]
if ok {
- entry.Data["fields.type"] = v
+ fields["fields.type"] = v
}
- entry.Data["type"] = f.Type
+ fields["type"] = f.Type
}
- serialized, err := json.Marshal(entry.Data)
+ serialized, err := json.Marshal(fields)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
diff --git a/go/src/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go
diff --git a/go/src/github.com/Sirupsen/logrus/hook_test.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hook_test.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/hook_test.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/hook_test.go
diff --git a/go/src/github.com/Sirupsen/logrus/hooks.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/hooks.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks.go
diff --git a/go/src/github.com/Sirupsen/logrus/hooks/syslog/README.md b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/hooks/syslog/README.md
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
diff --git a/go/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
similarity index 89%
rename from go/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
index b6fa3746..a36e2003 100644
--- a/go/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
@@ -1,3 +1,5 @@
+// +build !windows,!nacl,!plan9
+
package logrus_syslog
import (
@@ -48,12 +50,5 @@ func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
}
func (hook *SyslogHook) Levels() []logrus.Level {
- return []logrus.Level{
- logrus.PanicLevel,
- logrus.FatalLevel,
- logrus.ErrorLevel,
- logrus.WarnLevel,
- logrus.InfoLevel,
- logrus.DebugLevel,
- }
+ return logrus.AllLevels
}
diff --git a/go/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
diff --git a/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/test/test.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/test/test.go
new file mode 100644
index 00000000..06881253
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/test/test.go
@@ -0,0 +1,67 @@
+package test
+
+import (
+ "io/ioutil"
+
+ "github.com/Sirupsen/logrus"
+)
+
+// test.Hook is a hook designed for dealing with logs in test scenarios.
+type Hook struct {
+ Entries []*logrus.Entry
+}
+
+// Installs a test hook for the global logger.
+func NewGlobal() *Hook {
+
+ hook := new(Hook)
+ logrus.AddHook(hook)
+
+ return hook
+
+}
+
+// Installs a test hook for a given local logger.
+func NewLocal(logger *logrus.Logger) *Hook {
+
+ hook := new(Hook)
+ logger.Hooks.Add(hook)
+
+ return hook
+
+}
+
+// Creates a discarding logger and installs the test hook.
+func NewNullLogger() (*logrus.Logger, *Hook) {
+
+ logger := logrus.New()
+ logger.Out = ioutil.Discard
+
+ return logger, NewLocal(logger)
+
+}
+
+func (t *Hook) Fire(e *logrus.Entry) error {
+ t.Entries = append(t.Entries, e)
+ return nil
+}
+
+func (t *Hook) Levels() []logrus.Level {
+ return logrus.AllLevels
+}
+
+// LastEntry returns the last entry that was logged or nil.
+func (t *Hook) LastEntry() (l *logrus.Entry) {
+
+ if i := len(t.Entries) - 1; i < 0 {
+ return nil
+ } else {
+ return t.Entries[i]
+ }
+
+}
+
+// Reset removes all Entries from this test hook.
+func (t *Hook) Reset() {
+ t.Entries = make([]*logrus.Entry, 0)
+}
diff --git a/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
new file mode 100644
index 00000000..d69455ba
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
@@ -0,0 +1,39 @@
+package test
+
+import (
+ "testing"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAllHooks(t *testing.T) {
+
+ assert := assert.New(t)
+
+ logger, hook := NewNullLogger()
+ assert.Nil(hook.LastEntry())
+ assert.Equal(0, len(hook.Entries))
+
+ logger.Error("Hello error")
+ assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+ assert.Equal("Hello error", hook.LastEntry().Message)
+ assert.Equal(1, len(hook.Entries))
+
+ logger.Warn("Hello warning")
+ assert.Equal(logrus.WarnLevel, hook.LastEntry().Level)
+ assert.Equal("Hello warning", hook.LastEntry().Message)
+ assert.Equal(2, len(hook.Entries))
+
+ hook.Reset()
+ assert.Nil(hook.LastEntry())
+ assert.Equal(0, len(hook.Entries))
+
+ hook = NewGlobal()
+
+ logrus.Error("Hello error")
+ assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+ assert.Equal("Hello error", hook.LastEntry().Message)
+ assert.Equal(1, len(hook.Entries))
+
+}
diff --git a/go/src/github.com/Sirupsen/logrus/json_formatter.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/json_formatter.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/json_formatter.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/json_formatter.go
diff --git a/go/src/github.com/Sirupsen/logrus/json_formatter_test.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/json_formatter_test.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/json_formatter_test.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/json_formatter_test.go
diff --git a/go/src/github.com/Sirupsen/logrus/logger.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/logger.go
similarity index 96%
rename from go/src/github.com/Sirupsen/logrus/logger.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/logger.go
index fd9804c6..2fdb2317 100644
--- a/go/src/github.com/Sirupsen/logrus/logger.go
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/logger.go
@@ -64,6 +64,12 @@ func (logger *Logger) WithFields(fields Fields) *Entry {
return NewEntry(logger).WithFields(fields)
}
+// Add an error as single field to the log entry. All it does is call
+// `WithError` for the given `error`.
+func (logger *Logger) WithError(err error) *Entry {
+ return NewEntry(logger).WithError(err)
+}
+
func (logger *Logger) Debugf(format string, args ...interface{}) {
if logger.Level >= DebugLevel {
NewEntry(logger).Debugf(format, args...)
diff --git a/go/src/github.com/Sirupsen/logrus/logrus.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/logrus.go
similarity index 92%
rename from go/src/github.com/Sirupsen/logrus/logrus.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/logrus.go
index 0c09fbc2..1e9670d8 100644
--- a/go/src/github.com/Sirupsen/logrus/logrus.go
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/logrus.go
@@ -3,6 +3,7 @@ package logrus
import (
"fmt"
"log"
+ "strings"
)
// Fields type, used to pass to `WithFields`.
@@ -33,7 +34,7 @@ func (level Level) String() string {
// ParseLevel takes a string level and returns the Logrus log level constant.
func ParseLevel(lvl string) (Level, error) {
- switch lvl {
+ switch strings.ToLower(lvl) {
case "panic":
return PanicLevel, nil
case "fatal":
@@ -52,6 +53,16 @@ func ParseLevel(lvl string) (Level, error) {
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
}
+// A constant exposing all logging levels
+var AllLevels = []Level{
+ PanicLevel,
+ FatalLevel,
+ ErrorLevel,
+ WarnLevel,
+ InfoLevel,
+ DebugLevel,
+}
+
// These are the different logging levels. You can set the logging level to log
// on your instance of logger, obtained with `logrus.New()`.
const (
diff --git a/go/src/github.com/Sirupsen/logrus/logrus_test.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/logrus_test.go
similarity index 90%
rename from go/src/github.com/Sirupsen/logrus/logrus_test.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/logrus_test.go
index efaacea2..2cf03f2f 100644
--- a/go/src/github.com/Sirupsen/logrus/logrus_test.go
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/logrus_test.go
@@ -255,30 +255,58 @@ func TestParseLevel(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, PanicLevel, l)
+ l, err = ParseLevel("PANIC")
+ assert.Nil(t, err)
+ assert.Equal(t, PanicLevel, l)
+
l, err = ParseLevel("fatal")
assert.Nil(t, err)
assert.Equal(t, FatalLevel, l)
+ l, err = ParseLevel("FATAL")
+ assert.Nil(t, err)
+ assert.Equal(t, FatalLevel, l)
+
l, err = ParseLevel("error")
assert.Nil(t, err)
assert.Equal(t, ErrorLevel, l)
+ l, err = ParseLevel("ERROR")
+ assert.Nil(t, err)
+ assert.Equal(t, ErrorLevel, l)
+
l, err = ParseLevel("warn")
assert.Nil(t, err)
assert.Equal(t, WarnLevel, l)
+ l, err = ParseLevel("WARN")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
l, err = ParseLevel("warning")
assert.Nil(t, err)
assert.Equal(t, WarnLevel, l)
+ l, err = ParseLevel("WARNING")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
l, err = ParseLevel("info")
assert.Nil(t, err)
assert.Equal(t, InfoLevel, l)
+ l, err = ParseLevel("INFO")
+ assert.Nil(t, err)
+ assert.Equal(t, InfoLevel, l)
+
l, err = ParseLevel("debug")
assert.Nil(t, err)
assert.Equal(t, DebugLevel, l)
+ l, err = ParseLevel("DEBUG")
+ assert.Nil(t, err)
+ assert.Equal(t, DebugLevel, l)
+
l, err = ParseLevel("invalid")
assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
}
@@ -299,3 +327,18 @@ func TestGetSetLevelRace(t *testing.T) {
}
wg.Wait()
}
+
+func TestLoggingRace(t *testing.T) {
+ logger := New()
+
+ var wg sync.WaitGroup
+ wg.Add(100)
+
+ for i := 0; i < 100; i++ {
+ go func() {
+ logger.Info("info")
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
diff --git a/go/src/github.com/Sirupsen/logrus/terminal_bsd.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/terminal_bsd.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
diff --git a/go/src/github.com/Sirupsen/logrus/terminal_linux.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_linux.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/terminal_linux.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_linux.go
diff --git a/go/src/github.com/Sirupsen/logrus/terminal_notwindows.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
similarity index 83%
rename from go/src/github.com/Sirupsen/logrus/terminal_notwindows.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
index 4bb53760..b343b3a3 100644
--- a/go/src/github.com/Sirupsen/logrus/terminal_notwindows.go
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
@@ -12,9 +12,9 @@ import (
"unsafe"
)
-// IsTerminal returns true if the given file descriptor is a terminal.
+// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool {
- fd := syscall.Stdout
+ fd := syscall.Stderr
var termios Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
diff --git a/go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_solaris.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
new file mode 100644
index 00000000..3e70bf7b
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
@@ -0,0 +1,15 @@
+// +build solaris
+
+package logrus
+
+import (
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal() bool {
+ _, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
+ return err == nil
+}
diff --git a/go/src/github.com/Sirupsen/logrus/terminal_windows.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_windows.go
similarity index 85%
rename from go/src/github.com/Sirupsen/logrus/terminal_windows.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_windows.go
index 2e09f6f7..0146845d 100644
--- a/go/src/github.com/Sirupsen/logrus/terminal_windows.go
+++ b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/terminal_windows.go
@@ -18,9 +18,9 @@ var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
)
-// IsTerminal returns true if the given file descriptor is a terminal.
+// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool {
- fd := syscall.Stdout
+ fd := syscall.Stderr
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
diff --git a/go/src/github.com/Sirupsen/logrus/text_formatter.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/text_formatter.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/text_formatter.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/text_formatter.go
diff --git a/go/src/github.com/Sirupsen/logrus/text_formatter_test.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/text_formatter_test.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/text_formatter_test.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/text_formatter_test.go
diff --git a/go/src/github.com/Sirupsen/logrus/writer.go b/go/src/goproxy/vendor/github.com/Sirupsen/logrus/writer.go
similarity index 100%
rename from go/src/github.com/Sirupsen/logrus/writer.go
rename to go/src/goproxy/vendor/github.com/Sirupsen/logrus/writer.go
diff --git a/go/src/goproxy/vendor/github.com/docker/go-units/CONTRIBUTING.md b/go/src/goproxy/vendor/github.com/docker/go-units/CONTRIBUTING.md
new file mode 100644
index 00000000..9ea86d78
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/docker/go-units/CONTRIBUTING.md
@@ -0,0 +1,67 @@
+# Contributing to go-units
+
+Want to hack on go-units? Awesome! Here are instructions to get you started.
+
+go-units is a part of the [Docker](https://www.docker.com) project, and follows
+the same rules and principles. If you're already familiar with the way
+Docker does things, you'll feel right at home.
+
+Otherwise, go read Docker's
+[contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md),
+[issue triaging](https://github.com/docker/docker/blob/master/project/ISSUE-TRIAGE.md),
+[review process](https://github.com/docker/docker/blob/master/project/REVIEWING.md) and
+[branches and tags](https://github.com/docker/docker/blob/master/project/BRANCHES-AND-TAGS.md).
+
+### Sign your work
+
+The sign-off is a simple line at the end of the explanation for the patch. Your
+signature certifies that you wrote the patch or otherwise have the right to pass
+it on as an open-source patch. The rules are pretty simple: if you can certify
+the below (from [developercertificate.org](http://developercertificate.org/)):
+
+```
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+660 York Street, Suite 102,
+San Francisco, CA 94110 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+(d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+```
+
+Then you just add a line to every git commit message:
+
+ Signed-off-by: Joe Smith
+
+Use your real name (sorry, no pseudonyms or anonymous contributions.)
+
+If you set your `user.name` and `user.email` git configs, you can sign your
+commit automatically with `git commit -s`.
diff --git a/go/src/goproxy/vendor/github.com/docker/go-units/LICENSE.code b/go/src/goproxy/vendor/github.com/docker/go-units/LICENSE.code
new file mode 100644
index 00000000..b55b37bc
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/docker/go-units/LICENSE.code
@@ -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/go/src/goproxy/vendor/github.com/docker/go-units/LICENSE.docs b/go/src/goproxy/vendor/github.com/docker/go-units/LICENSE.docs
new file mode 100644
index 00000000..e26cd4fc
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/docker/go-units/LICENSE.docs
@@ -0,0 +1,425 @@
+Attribution-ShareAlike 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+ Considerations for licensors: Our public licenses are
+ intended for use by those authorized to give the public
+ permission to use material in ways otherwise restricted by
+ copyright and certain other rights. Our licenses are
+ irrevocable. Licensors should read and understand the terms
+ and conditions of the license they choose before applying it.
+ Licensors should also secure all rights necessary before
+ applying our licenses so that the public can reuse the
+ material as expected. Licensors should clearly mark any
+ material not subject to the license. This includes other CC-
+ licensed material, or material used under an exception or
+ limitation to copyright. More considerations for licensors:
+ wiki.creativecommons.org/Considerations_for_licensors
+
+ Considerations for the public: By using one of our public
+ licenses, a licensor grants the public permission to use the
+ licensed material under specified terms and conditions. If
+ the licensor's permission is not necessary for any reason--for
+ example, because of any applicable exception or limitation to
+ copyright--then that use is not regulated by the license. Our
+ licenses grant only permissions under copyright and certain
+ other rights that a licensor has authority to grant. Use of
+ the licensed material may still be restricted for other
+ reasons, including because others have copyright or other
+ rights in the material. A licensor may make special requests,
+ such as asking that all changes be marked or described.
+ Although not required by our licenses, you are encouraged to
+ respect those requests where reasonable. More_considerations
+ for the public:
+ wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution-ShareAlike 4.0 International Public
+License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution-ShareAlike 4.0 International Public License ("Public
+License"). To the extent this Public License may be interpreted as a
+contract, You are granted the Licensed Rights in consideration of Your
+acceptance of these terms and conditions, and the Licensor grants You
+such rights in consideration of benefits the Licensor receives from
+making the Licensed Material available under these terms and
+conditions.
+
+
+Section 1 -- Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+ Rights that is derived from or based upon the Licensed Material
+ and in which the Licensed Material is translated, altered,
+ arranged, transformed, or otherwise modified in a manner requiring
+ permission under the Copyright and Similar Rights held by the
+ Licensor. For purposes of this Public License, where the Licensed
+ Material is a musical work, performance, or sound recording,
+ Adapted Material is always produced where the Licensed Material is
+ synched in timed relation with a moving image.
+
+ b. Adapter's License means the license You apply to Your Copyright
+ and Similar Rights in Your contributions to Adapted Material in
+ accordance with the terms and conditions of this Public License.
+
+ c. BY-SA Compatible License means a license listed at
+ creativecommons.org/compatiblelicenses, approved by Creative
+ Commons as essentially the equivalent of this Public License.
+
+ d. Copyright and Similar Rights means copyright and/or similar rights
+ closely related to copyright including, without limitation,
+ performance, broadcast, sound recording, and Sui Generis Database
+ Rights, without regard to how the rights are labeled or
+ categorized. For purposes of this Public License, the rights
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
+ Rights.
+
+ e. Effective Technological Measures means those measures that, in the
+ absence of proper authority, may not be circumvented under laws
+ fulfilling obligations under Article 11 of the WIPO Copyright
+ Treaty adopted on December 20, 1996, and/or similar international
+ agreements.
+
+ f. Exceptions and Limitations means fair use, fair dealing, and/or
+ any other exception or limitation to Copyright and Similar Rights
+ that applies to Your use of the Licensed Material.
+
+ g. License Elements means the license attributes listed in the name
+ of a Creative Commons Public License. The License Elements of this
+ Public License are Attribution and ShareAlike.
+
+ h. Licensed Material means the artistic or literary work, database,
+ or other material to which the Licensor applied this Public
+ License.
+
+ i. Licensed Rights means the rights granted to You subject to the
+ terms and conditions of this Public License, which are limited to
+ all Copyright and Similar Rights that apply to Your use of the
+ Licensed Material and that the Licensor has authority to license.
+
+ j. Licensor means the individual(s) or entity(ies) granting rights
+ under this Public License.
+
+ k. Share means to provide material to the public by any means or
+ process that requires permission under the Licensed Rights, such
+ as reproduction, public display, public performance, distribution,
+ dissemination, communication, or importation, and to make material
+ available to the public including in ways that members of the
+ public may access the material from a place and at a time
+ individually chosen by them.
+
+ l. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament and of
+ the Council of 11 March 1996 on the legal protection of databases,
+ as amended and/or succeeded, as well as other essentially
+ equivalent rights anywhere in the world.
+
+ m. You means the individual or entity exercising the Licensed Rights
+ under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+ a. License grant.
+
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You a worldwide, royalty-free,
+ non-sublicensable, non-exclusive, irrevocable license to
+ exercise the Licensed Rights in the Licensed Material to:
+
+ a. reproduce and Share the Licensed Material, in whole or
+ in part; and
+
+ b. produce, reproduce, and Share Adapted Material.
+
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
+ Exceptions and Limitations apply to Your use, this Public
+ License does not apply, and You do not need to comply with
+ its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section
+ 6(a).
+
+ 4. Media and formats; technical modifications allowed. The
+ Licensor authorizes You to exercise the Licensed Rights in
+ all media and formats whether now known or hereafter created,
+ and to make technical modifications necessary to do so. The
+ Licensor waives and/or agrees not to assert any right or
+ authority to forbid You from making technical modifications
+ necessary to exercise the Licensed Rights, including
+ technical modifications necessary to circumvent Effective
+ Technological Measures. For purposes of this Public License,
+ simply making modifications authorized by this Section 2(a)
+ (4) never produces Adapted Material.
+
+ 5. Downstream recipients.
+
+ a. Offer from the Licensor -- Licensed Material. Every
+ recipient of the Licensed Material automatically
+ receives an offer from the Licensor to exercise the
+ Licensed Rights under the terms and conditions of this
+ Public License.
+
+ b. Additional offer from the Licensor -- Adapted Material.
+ Every recipient of Adapted Material from You
+ automatically receives an offer from the Licensor to
+ exercise the Licensed Rights in the Adapted Material
+ under the conditions of the Adapter's License You apply.
+
+ c. No downstream restrictions. You may not offer or impose
+ any additional or different terms or conditions on, or
+ apply any Effective Technological Measures to, the
+ Licensed Material if doing so restricts exercise of the
+ Licensed Rights by any recipient of the Licensed
+ Material.
+
+ 6. No endorsement. Nothing in this Public License constitutes or
+ may be construed as permission to assert or imply that You
+ are, or that Your use of the Licensed Material is, connected
+ with, or sponsored, endorsed, or granted official status by,
+ the Licensor or others designated to receive attribution as
+ provided in Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+ 1. Moral rights, such as the right of integrity, are not
+ licensed under this Public License, nor are publicity,
+ privacy, and/or other similar personality rights; however, to
+ the extent possible, the Licensor waives and/or agrees not to
+ assert any such rights held by the Licensor to the limited
+ extent necessary to allow You to exercise the Licensed
+ Rights, but not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this
+ Public License.
+
+ 3. To the extent possible, the Licensor waives any right to
+ collect royalties from You for the exercise of the Licensed
+ Rights, whether directly or through a collecting society
+ under any voluntary or waivable statutory or compulsory
+ licensing scheme. In all other cases the Licensor expressly
+ reserves any right to collect such royalties.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+ a. Attribution.
+
+ 1. If You Share the Licensed Material (including in modified
+ form), You must:
+
+ a. retain the following if it is supplied by the Licensor
+ with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed
+ Material and any others designated to receive
+ attribution, in any reasonable manner requested by
+ the Licensor (including by pseudonym if
+ designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of
+ warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the
+ extent reasonably practicable;
+
+ b. indicate if You modified the Licensed Material and
+ retain an indication of any previous modifications; and
+
+ c. indicate the Licensed Material is licensed under this
+ Public License, and include the text of, or the URI or
+ hyperlink to, this Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
+ reasonable manner based on the medium, means, and context in
+ which You Share the Licensed Material. For example, it may be
+ reasonable to satisfy the conditions by providing a URI or
+ hyperlink to a resource that includes the required
+ information.
+
+ 3. If requested by the Licensor, You must remove any of the
+ information required by Section 3(a)(1)(A) to the extent
+ reasonably practicable.
+
+ b. ShareAlike.
+
+ In addition to the conditions in Section 3(a), if You Share
+ Adapted Material You produce, the following conditions also apply.
+
+ 1. The Adapter's License You apply must be a Creative Commons
+ license with the same License Elements, this version or
+ later, or a BY-SA Compatible License.
+
+ 2. You must include the text of, or the URI or hyperlink to, the
+ Adapter's License You apply. You may satisfy this condition
+ in any reasonable manner based on the medium, means, and
+ context in which You Share Adapted Material.
+
+ 3. You may not offer or impose any additional or different terms
+ or conditions on, or apply any Effective Technological
+ Measures to, Adapted Material that restrict exercise of the
+ rights granted under the Adapter's License You apply.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+ to extract, reuse, reproduce, and Share all or a substantial
+ portion of the contents of the database;
+
+ b. if You include all or a substantial portion of the database
+ contents in a database in which You have Sui Generis Database
+ Rights, then the database in which You have Sui Generis Database
+ Rights (but not its individual contents) is Adapted Material,
+
+ including for purposes of Section 3(b); and
+ c. You must comply with the conditions in Section 3(a) if You Share
+ all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+ c. The disclaimer of warranties and limitation of liability provided
+ above shall be interpreted in a manner that, to the extent
+ possible, most closely approximates an absolute disclaimer and
+ waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+ Similar Rights licensed here. However, if You fail to comply with
+ this Public License, then Your rights under this Public License
+ terminate automatically.
+
+ b. Where Your right to use the Licensed Material has terminated under
+ Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided
+ it is cured within 30 days of Your discovery of the
+ violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations
+ of this Public License.
+
+ c. For the avoidance of doubt, the Licensor may also offer the
+ Licensed Material under separate terms or conditions or stop
+ distributing the Licensed Material at any time; however, doing so
+ will not terminate this Public License.
+
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+ License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+ terms or conditions communicated by You unless expressly agreed.
+
+ b. Any arrangements, understandings, or agreements regarding the
+ Licensed Material not stated herein are separate from and
+ independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and
+ shall not be interpreted to, reduce, limit, restrict, or impose
+ conditions on any use of the Licensed Material that could lawfully
+ be made without permission under this Public License.
+
+ b. To the extent possible, if any provision of this Public License is
+ deemed unenforceable, it shall be automatically reformed to the
+ minimum extent necessary to make it enforceable. If the provision
+ cannot be reformed, it shall be severed from this Public License
+ without affecting the enforceability of the remaining terms and
+ conditions.
+
+ c. No term or condition of this Public License will be waived and no
+ failure to comply consented to unless expressly agreed to by the
+ Licensor.
+
+ d. Nothing in this Public License constitutes or may be interpreted
+ as a limitation upon, or waiver of, any privileges and immunities
+ that apply to the Licensor or You, including from the legal
+ processes of any jurisdiction or authority.
+
+
+=======================================================================
+
+Creative Commons is not a party to its public licenses.
+Notwithstanding, Creative Commons may elect to apply one of its public
+licenses to material it publishes and in those instances will be
+considered the "Licensor." Except for the limited purpose of indicating
+that material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the public
+licenses.
+
+Creative Commons may be contacted at creativecommons.org.
diff --git a/go/src/goproxy/vendor/github.com/docker/go-units/MAINTAINERS b/go/src/goproxy/vendor/github.com/docker/go-units/MAINTAINERS
new file mode 100644
index 00000000..477be8b2
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/docker/go-units/MAINTAINERS
@@ -0,0 +1,27 @@
+# go-connections maintainers file
+#
+# This file describes who runs the docker/go-connections project and how.
+# This is a living document - if you see something out of date or missing, speak up!
+#
+# It is structured to be consumable by both humans and programs.
+# To extract its contents programmatically, use any TOML-compliant parser.
+#
+# This file is compiled into the MAINTAINERS file in docker/opensource.
+#
+[Org]
+ [Org."Core maintainers"]
+ people = [
+ "calavera",
+ ]
+
+[people]
+
+# A reference list of all people associated with the project.
+# All other sections should refer to people by their canonical key
+# in the people section.
+
+ # ADD YOURSELF HERE IN ALPHABETICAL ORDER
+ [people.calavera]
+ Name = "David Calavera"
+ Email = "david.calavera@gmail.com"
+ GitHub = "calavera"
diff --git a/go/src/goproxy/vendor/github.com/docker/go-units/README.md b/go/src/goproxy/vendor/github.com/docker/go-units/README.md
new file mode 100644
index 00000000..3ce4d79d
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/docker/go-units/README.md
@@ -0,0 +1,18 @@
+[](https://godoc.org/github.com/docker/go-units)
+
+# Introduction
+
+go-units is a library to transform human friendly measurements into machine friendly values.
+
+## Usage
+
+See the [docs in godoc](https://godoc.org/github.com/docker/go-units) for examples and documentation.
+
+## Copyright and license
+
+Copyright © 2015 Docker, Inc. All rights reserved, except as follows. Code
+is released under the Apache 2.0 license. The README.md file, and files in the
+"docs" folder are licensed under the Creative Commons Attribution 4.0
+International License under the terms and conditions set forth in the file
+"LICENSE.docs". You may obtain a duplicate copy of the same license, titled
+CC-BY-SA-4.0, at http://creativecommons.org/licenses/by/4.0/.
diff --git a/go/src/goproxy/vendor/github.com/docker/go-units/circle.yml b/go/src/goproxy/vendor/github.com/docker/go-units/circle.yml
new file mode 100644
index 00000000..9043b354
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/docker/go-units/circle.yml
@@ -0,0 +1,11 @@
+dependencies:
+ post:
+ # install golint
+ - go get github.com/golang/lint/golint
+
+test:
+ pre:
+ # run analysis before tests
+ - go vet ./...
+ - test -z "$(golint ./... | tee /dev/stderr)"
+ - test -z "$(gofmt -s -l . | tee /dev/stderr)"
diff --git a/go/src/github.com/docker/docker/pkg/units/duration.go b/go/src/goproxy/vendor/github.com/docker/go-units/duration.go
old mode 100755
new mode 100644
similarity index 100%
rename from go/src/github.com/docker/docker/pkg/units/duration.go
rename to go/src/goproxy/vendor/github.com/docker/go-units/duration.go
diff --git a/go/src/github.com/docker/docker/pkg/units/duration_test.go b/go/src/goproxy/vendor/github.com/docker/go-units/duration_test.go
old mode 100755
new mode 100644
similarity index 54%
rename from go/src/github.com/docker/docker/pkg/units/duration_test.go
rename to go/src/goproxy/vendor/github.com/docker/go-units/duration_test.go
index fcfb6b7b..63baa515
--- a/go/src/github.com/docker/docker/pkg/units/duration_test.go
+++ b/go/src/goproxy/vendor/github.com/docker/go-units/duration_test.go
@@ -1,10 +1,45 @@
package units
import (
+ "fmt"
"testing"
"time"
)
+func ExampleHumanDuration() {
+ fmt.Println(HumanDuration(450 * time.Millisecond))
+ fmt.Println(HumanDuration(47 * time.Second))
+ fmt.Println(HumanDuration(1 * time.Minute))
+ fmt.Println(HumanDuration(3 * time.Minute))
+ fmt.Println(HumanDuration(35 * time.Minute))
+ fmt.Println(HumanDuration(35*time.Minute + 40*time.Second))
+ fmt.Println(HumanDuration(1 * time.Hour))
+ fmt.Println(HumanDuration(1*time.Hour + 45*time.Minute))
+ fmt.Println(HumanDuration(3 * time.Hour))
+ fmt.Println(HumanDuration(3*time.Hour + 59*time.Minute))
+ fmt.Println(HumanDuration(3*time.Hour + 60*time.Minute))
+ fmt.Println(HumanDuration(24 * time.Hour))
+ fmt.Println(HumanDuration(24*time.Hour + 12*time.Hour))
+ fmt.Println(HumanDuration(2 * 24 * time.Hour))
+ fmt.Println(HumanDuration(7 * 24 * time.Hour))
+ fmt.Println(HumanDuration(13*24*time.Hour + 5*time.Hour))
+ fmt.Println(HumanDuration(2 * 7 * 24 * time.Hour))
+ fmt.Println(HumanDuration(2*7*24*time.Hour + 4*24*time.Hour))
+ fmt.Println(HumanDuration(3 * 7 * 24 * time.Hour))
+ fmt.Println(HumanDuration(4 * 7 * 24 * time.Hour))
+ fmt.Println(HumanDuration(4*7*24*time.Hour + 3*24*time.Hour))
+ fmt.Println(HumanDuration(1 * 30 * 24 * time.Hour))
+ fmt.Println(HumanDuration(1*30*24*time.Hour + 2*7*24*time.Hour))
+ fmt.Println(HumanDuration(2 * 30 * 24 * time.Hour))
+ fmt.Println(HumanDuration(3*30*24*time.Hour + 1*7*24*time.Hour))
+ fmt.Println(HumanDuration(5*30*24*time.Hour + 2*7*24*time.Hour))
+ fmt.Println(HumanDuration(13 * 30 * 24 * time.Hour))
+ fmt.Println(HumanDuration(23 * 30 * 24 * time.Hour))
+ fmt.Println(HumanDuration(24 * 30 * 24 * time.Hour))
+ fmt.Println(HumanDuration(24*30*24*time.Hour + 2*7*24*time.Hour))
+ fmt.Println(HumanDuration(3*365*24*time.Hour + 2*30*24*time.Hour))
+}
+
func TestHumanDuration(t *testing.T) {
// Useful duration abstractions
day := 24 * time.Hour
diff --git a/go/src/github.com/docker/docker/pkg/units/size.go b/go/src/goproxy/vendor/github.com/docker/go-units/size.go
old mode 100755
new mode 100644
similarity index 90%
rename from go/src/github.com/docker/docker/pkg/units/size.go
rename to go/src/goproxy/vendor/github.com/docker/go-units/size.go
index 3b59daff..989edd29
--- a/go/src/github.com/docker/docker/pkg/units/size.go
+++ b/go/src/goproxy/vendor/github.com/docker/go-units/size.go
@@ -31,7 +31,7 @@ type unitMap map[string]int64
var (
decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB}
binaryMap = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB}
- sizeRegex = regexp.MustCompile(`^(\d+)([kKmMgGtTpP])?[bB]?$`)
+ sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[bB]?$`)
)
var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
@@ -77,19 +77,19 @@ func RAMInBytes(size string) (int64, error) {
// Parses the human-readable size string into the amount it represents.
func parseSize(sizeStr string, uMap unitMap) (int64, error) {
matches := sizeRegex.FindStringSubmatch(sizeStr)
- if len(matches) != 3 {
+ if len(matches) != 4 {
return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
}
- size, err := strconv.ParseInt(matches[1], 10, 0)
+ size, err := strconv.ParseFloat(matches[1], 64)
if err != nil {
return -1, err
}
- unitPrefix := strings.ToLower(matches[2])
+ unitPrefix := strings.ToLower(matches[3])
if mul, ok := uMap[unitPrefix]; ok {
- size *= mul
+ size *= float64(mul)
}
- return size, nil
+ return int64(size), nil
}
diff --git a/go/src/github.com/docker/docker/pkg/units/size_test.go b/go/src/goproxy/vendor/github.com/docker/go-units/size_test.go
old mode 100755
new mode 100644
similarity index 66%
rename from go/src/github.com/docker/docker/pkg/units/size_test.go
rename to go/src/goproxy/vendor/github.com/docker/go-units/size_test.go
index 67c3b81e..003bc89a
--- a/go/src/github.com/docker/docker/pkg/units/size_test.go
+++ b/go/src/goproxy/vendor/github.com/docker/go-units/size_test.go
@@ -1,12 +1,64 @@
package units
import (
+ "fmt"
"reflect"
"runtime"
"strings"
"testing"
)
+func ExampleBytesSize() {
+ fmt.Println(BytesSize(1024))
+ fmt.Println(BytesSize(1024 * 1024))
+ fmt.Println(BytesSize(1048576))
+ fmt.Println(BytesSize(2 * MiB))
+ fmt.Println(BytesSize(3.42 * GiB))
+ fmt.Println(BytesSize(5.372 * TiB))
+ fmt.Println(BytesSize(2.22 * PiB))
+}
+
+func ExampleHumanSize() {
+ fmt.Println(HumanSize(1000))
+ fmt.Println(HumanSize(1024))
+ fmt.Println(HumanSize(1000000))
+ fmt.Println(HumanSize(1048576))
+ fmt.Println(HumanSize(2 * MB))
+ fmt.Println(HumanSize(float64(3.42 * GB)))
+ fmt.Println(HumanSize(float64(5.372 * TB)))
+ fmt.Println(HumanSize(float64(2.22 * PB)))
+}
+
+func ExampleFromHumanSize() {
+ fmt.Println(FromHumanSize("32"))
+ fmt.Println(FromHumanSize("32b"))
+ fmt.Println(FromHumanSize("32B"))
+ fmt.Println(FromHumanSize("32k"))
+ fmt.Println(FromHumanSize("32K"))
+ fmt.Println(FromHumanSize("32kb"))
+ fmt.Println(FromHumanSize("32Kb"))
+ fmt.Println(FromHumanSize("32Mb"))
+ fmt.Println(FromHumanSize("32Gb"))
+ fmt.Println(FromHumanSize("32Tb"))
+ fmt.Println(FromHumanSize("32Pb"))
+}
+
+func ExampleRAMInBytes() {
+ fmt.Println(RAMInBytes("32"))
+ fmt.Println(RAMInBytes("32b"))
+ fmt.Println(RAMInBytes("32B"))
+ fmt.Println(RAMInBytes("32k"))
+ fmt.Println(RAMInBytes("32K"))
+ fmt.Println(RAMInBytes("32kb"))
+ fmt.Println(RAMInBytes("32Kb"))
+ fmt.Println(RAMInBytes("32Mb"))
+ fmt.Println(RAMInBytes("32Gb"))
+ fmt.Println(RAMInBytes("32Tb"))
+ fmt.Println(RAMInBytes("32Pb"))
+ fmt.Println(RAMInBytes("32PB"))
+ fmt.Println(RAMInBytes("32P"))
+}
+
func TestBytesSize(t *testing.T) {
assertEquals(t, "1 KiB", BytesSize(1024))
assertEquals(t, "1 MiB", BytesSize(1024*1024))
@@ -41,13 +93,15 @@ func TestFromHumanSize(t *testing.T) {
assertSuccessEquals(t, 32*TB, FromHumanSize, "32Tb")
assertSuccessEquals(t, 32*PB, FromHumanSize, "32Pb")
+ assertSuccessEquals(t, 32.5*KB, FromHumanSize, "32.5kB")
+ assertSuccessEquals(t, 32.5*KB, FromHumanSize, "32.5 kB")
+ assertSuccessEquals(t, 32, FromHumanSize, "32.5 B")
+
assertError(t, FromHumanSize, "")
assertError(t, FromHumanSize, "hello")
assertError(t, FromHumanSize, "-32")
- assertError(t, FromHumanSize, "32.3")
+ assertError(t, FromHumanSize, ".3kB")
assertError(t, FromHumanSize, " 32 ")
- assertError(t, FromHumanSize, "32.3Kb")
- assertError(t, FromHumanSize, "32 mb")
assertError(t, FromHumanSize, "32m b")
assertError(t, FromHumanSize, "32bm")
}
@@ -67,13 +121,14 @@ func TestRAMInBytes(t *testing.T) {
assertSuccessEquals(t, 32*PiB, RAMInBytes, "32PB")
assertSuccessEquals(t, 32*PiB, RAMInBytes, "32P")
+ assertSuccessEquals(t, 32, RAMInBytes, "32.3")
+ tmp := 32.3 * MiB
+ assertSuccessEquals(t, int64(tmp), RAMInBytes, "32.3 mb")
+
assertError(t, RAMInBytes, "")
assertError(t, RAMInBytes, "hello")
assertError(t, RAMInBytes, "-32")
- assertError(t, RAMInBytes, "32.3")
assertError(t, RAMInBytes, " 32 ")
- assertError(t, RAMInBytes, "32.3Kb")
- assertError(t, RAMInBytes, "32 mb")
assertError(t, RAMInBytes, "32m b")
assertError(t, RAMInBytes, "32bm")
}
diff --git a/go/src/goproxy/vendor/github.com/docker/go-units/ulimit.go b/go/src/goproxy/vendor/github.com/docker/go-units/ulimit.go
new file mode 100644
index 00000000..5ac7fd82
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/docker/go-units/ulimit.go
@@ -0,0 +1,118 @@
+package units
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// Ulimit is a human friendly version of Rlimit.
+type Ulimit struct {
+ Name string
+ Hard int64
+ Soft int64
+}
+
+// Rlimit specifies the resource limits, such as max open files.
+type Rlimit struct {
+ Type int `json:"type,omitempty"`
+ Hard uint64 `json:"hard,omitempty"`
+ Soft uint64 `json:"soft,omitempty"`
+}
+
+const (
+ // magic numbers for making the syscall
+ // some of these are defined in the syscall package, but not all.
+ // Also since Windows client doesn't get access to the syscall package, need to
+ // define these here
+ rlimitAs = 9
+ rlimitCore = 4
+ rlimitCPU = 0
+ rlimitData = 2
+ rlimitFsize = 1
+ rlimitLocks = 10
+ rlimitMemlock = 8
+ rlimitMsgqueue = 12
+ rlimitNice = 13
+ rlimitNofile = 7
+ rlimitNproc = 6
+ rlimitRss = 5
+ rlimitRtprio = 14
+ rlimitRttime = 15
+ rlimitSigpending = 11
+ rlimitStack = 3
+)
+
+var ulimitNameMapping = map[string]int{
+ //"as": rlimitAs, // Disabled since this doesn't seem usable with the way Docker inits a container.
+ "core": rlimitCore,
+ "cpu": rlimitCPU,
+ "data": rlimitData,
+ "fsize": rlimitFsize,
+ "locks": rlimitLocks,
+ "memlock": rlimitMemlock,
+ "msgqueue": rlimitMsgqueue,
+ "nice": rlimitNice,
+ "nofile": rlimitNofile,
+ "nproc": rlimitNproc,
+ "rss": rlimitRss,
+ "rtprio": rlimitRtprio,
+ "rttime": rlimitRttime,
+ "sigpending": rlimitSigpending,
+ "stack": rlimitStack,
+}
+
+// ParseUlimit parses and returns a Ulimit from the specified string.
+func ParseUlimit(val string) (*Ulimit, error) {
+ parts := strings.SplitN(val, "=", 2)
+ if len(parts) != 2 {
+ return nil, fmt.Errorf("invalid ulimit argument: %s", val)
+ }
+
+ if _, exists := ulimitNameMapping[parts[0]]; !exists {
+ return nil, fmt.Errorf("invalid ulimit type: %s", parts[0])
+ }
+
+ var (
+ soft int64
+ hard = &soft // default to soft in case no hard was set
+ temp int64
+ err error
+ )
+ switch limitVals := strings.Split(parts[1], ":"); len(limitVals) {
+ case 2:
+ temp, err = strconv.ParseInt(limitVals[1], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ hard = &temp
+ fallthrough
+ case 1:
+ soft, err = strconv.ParseInt(limitVals[0], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ default:
+ return nil, fmt.Errorf("too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1])
+ }
+
+ if soft > *hard {
+ return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: %d > %d", soft, *hard)
+ }
+
+ return &Ulimit{Name: parts[0], Soft: soft, Hard: *hard}, nil
+}
+
+// GetRlimit returns the RLimit corresponding to Ulimit.
+func (u *Ulimit) GetRlimit() (*Rlimit, error) {
+ t, exists := ulimitNameMapping[u.Name]
+ if !exists {
+ return nil, fmt.Errorf("invalid ulimit name %s", u.Name)
+ }
+
+ return &Rlimit{Type: t, Soft: uint64(u.Soft), Hard: uint64(u.Hard)}, nil
+}
+
+func (u *Ulimit) String() string {
+ return fmt.Sprintf("%s=%d:%d", u.Name, u.Soft, u.Hard)
+}
diff --git a/go/src/goproxy/vendor/github.com/docker/go-units/ulimit_test.go b/go/src/goproxy/vendor/github.com/docker/go-units/ulimit_test.go
new file mode 100644
index 00000000..3e7f10fc
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/docker/go-units/ulimit_test.go
@@ -0,0 +1,74 @@
+package units
+
+import (
+ "fmt"
+ "strconv"
+ "testing"
+)
+
+func ExampleParseUlimit() {
+ fmt.Println(ParseUlimit("nofile=512:1024"))
+ fmt.Println(ParseUlimit("nofile=1024"))
+ fmt.Println(ParseUlimit("cpu=2:4"))
+ fmt.Println(ParseUlimit("cpu=6"))
+}
+
+func TestParseUlimitValid(t *testing.T) {
+ u1 := &Ulimit{"nofile", 1024, 512}
+ if u2, _ := ParseUlimit("nofile=512:1024"); *u1 != *u2 {
+ t.Fatalf("expected %q, but got %q", u1, u2)
+ }
+}
+
+func TestParseUlimitInvalidLimitType(t *testing.T) {
+ if _, err := ParseUlimit("notarealtype=1024:1024"); err == nil {
+ t.Fatalf("expected error on invalid ulimit type")
+ }
+}
+
+func TestParseUlimitBadFormat(t *testing.T) {
+ if _, err := ParseUlimit("nofile:1024:1024"); err == nil {
+ t.Fatal("expected error on bad syntax")
+ }
+
+ if _, err := ParseUlimit("nofile"); err == nil {
+ t.Fatal("expected error on bad syntax")
+ }
+
+ if _, err := ParseUlimit("nofile="); err == nil {
+ t.Fatal("expected error on bad syntax")
+ }
+ if _, err := ParseUlimit("nofile=:"); err == nil {
+ t.Fatal("expected error on bad syntax")
+ }
+ if _, err := ParseUlimit("nofile=:1024"); err == nil {
+ t.Fatal("expected error on bad syntax")
+ }
+}
+
+func TestParseUlimitHardLessThanSoft(t *testing.T) {
+ if _, err := ParseUlimit("nofile=1024:1"); err == nil {
+ t.Fatal("expected error on hard limit less than soft limit")
+ }
+}
+
+func TestParseUlimitInvalidValueType(t *testing.T) {
+ if _, err := ParseUlimit("nofile=asdf"); err == nil {
+ t.Fatal("expected error on bad value type, but got no error")
+ } else if _, ok := err.(*strconv.NumError); !ok {
+ t.Fatalf("expected error on bad value type, but got `%s`", err)
+ }
+
+ if _, err := ParseUlimit("nofile=1024:asdf"); err == nil {
+ t.Fatal("expected error on bad value type, but got no error")
+ } else if _, ok := err.(*strconv.NumError); !ok {
+ t.Fatalf("expected error on bad value type, but got `%s`", err)
+ }
+}
+
+func TestUlimitStringOutput(t *testing.T) {
+ u := &Ulimit{"nofile", 1024, 512}
+ if s := u.String(); s != "nofile=512:1024" {
+ t.Fatal("expected String to return nofile=512:1024, but got", s)
+ }
+}
diff --git a/go/src/github.com/samalba/dockerclient/LICENSE b/go/src/goproxy/vendor/github.com/samalba/dockerclient/LICENSE
old mode 100755
new mode 100644
similarity index 100%
rename from go/src/github.com/samalba/dockerclient/LICENSE
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/LICENSE
diff --git a/go/src/github.com/samalba/dockerclient/README.md b/go/src/goproxy/vendor/github.com/samalba/dockerclient/README.md
old mode 100755
new mode 100644
similarity index 99%
rename from go/src/github.com/samalba/dockerclient/README.md
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/README.md
index 5a5027b8..6cad9bd3
--- a/go/src/github.com/samalba/dockerclient/README.md
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/README.md
@@ -63,7 +63,7 @@ func main() {
Cmd: []string{"bash"},
AttachStdin: true,
Tty: true}
- containerId, err := docker.CreateContainer(containerConfig, "foobar")
+ containerId, err := docker.CreateContainer(containerConfig, "foobar", nil)
if err != nil {
log.Fatal(err)
}
diff --git a/go/src/github.com/samalba/dockerclient/auth.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/auth.go
old mode 100755
new mode 100644
similarity index 82%
rename from go/src/github.com/samalba/dockerclient/auth.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/auth.go
index 48f5f90b..7c0a67f7
--- a/go/src/github.com/samalba/dockerclient/auth.go
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/auth.go
@@ -8,9 +8,10 @@ import (
// AuthConfig hold parameters for authenticating with the docker registry
type AuthConfig struct {
- Username string `json:"username,omitempty"`
- Password string `json:"password,omitempty"`
- Email string `json:"email,omitempty"`
+ Username string `json:"username,omitempty"`
+ Password string `json:"password,omitempty"`
+ Email string `json:"email,omitempty"`
+ RegistryToken string `json:"registrytoken,omitempty"`
}
// encode the auth configuration struct into base64 for the X-Registry-Auth header
diff --git a/go/src/github.com/samalba/dockerclient/auth_test.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/auth_test.go
similarity index 100%
rename from go/src/github.com/samalba/dockerclient/auth_test.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/auth_test.go
diff --git a/go/src/github.com/samalba/dockerclient/dockerclient.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/dockerclient.go
old mode 100755
new mode 100644
similarity index 86%
rename from go/src/github.com/samalba/dockerclient/dockerclient.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/dockerclient.go
index 96ea37fe..51a00b29
--- a/go/src/github.com/samalba/dockerclient/dockerclient.go
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/dockerclient.go
@@ -16,13 +16,23 @@ import (
"time"
)
+var _ Client = (*DockerClient)(nil)
+
const (
+ // APIVersion is currently hardcoded to v1.15
+ // TODO: bump the API version or allow users to choose which API version to
+ // use the client with. The current value does not make sense for many
+ // methods, such as ContainerStats, StartMonitorStats, and StopAllMonitorStats
+ // (v1.17) and
+ // ListVolumes, {Remove,Create}Volume, ListNetworks,
+ // {Inspect,Create,Connect,Disconnect,Remove}Network (v1.21)
APIVersion = "v1.15"
)
var (
- ErrImageNotFound = errors.New("Image not found")
- ErrNotFound = errors.New("Not found")
+ ErrImageNotFound = errors.New("Image not found")
+ ErrNotFound = errors.New("Not found")
+ ErrConnectionRefused = errors.New("Cannot connect to the docker engine endpoint")
defaultTimeout = 30 * time.Second
)
@@ -46,10 +56,10 @@ func (e Error) Error() string {
}
func NewDockerClient(daemonUrl string, tlsConfig *tls.Config) (*DockerClient, error) {
- return NewDockerClientTimeout(daemonUrl, tlsConfig, time.Duration(defaultTimeout))
+ return NewDockerClientTimeout(daemonUrl, tlsConfig, time.Duration(defaultTimeout), nil)
}
-func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout time.Duration) (*DockerClient, error) {
+func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout time.Duration, setUserTimeout tcpFunc) (*DockerClient, error) {
u, err := url.Parse(daemonUrl)
if err != nil {
return nil, err
@@ -61,7 +71,7 @@ func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout tim
u.Scheme = "https"
}
}
- httpClient := newHTTPClient(u, tlsConfig, timeout)
+ httpClient := newHTTPClient(u, tlsConfig, timeout, setUserTimeout)
return &DockerClient{u, httpClient, tlsConfig, 0, nil}, nil
}
@@ -100,6 +110,9 @@ func (client *DockerClient) doStreamRequest(method string, path string, in io.Re
if !strings.Contains(err.Error(), "connection refused") && client.TLSConfig == nil {
return nil, fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err)
}
+ if strings.Contains(err.Error(), "connection refused") {
+ return nil, ErrConnectionRefused
+ }
return nil, err
}
if resp.StatusCode == 404 {
@@ -184,7 +197,7 @@ func (client *DockerClient) InspectContainer(id string) (*ContainerInfo, error)
return info, nil
}
-func (client *DockerClient) CreateContainer(config *ContainerConfig, name string) (string, error) {
+func (client *DockerClient) CreateContainer(config *ContainerConfig, name string, auth *AuthConfig) (string, error) {
data, err := json.Marshal(config)
if err != nil {
return "", err
@@ -195,14 +208,22 @@ func (client *DockerClient) CreateContainer(config *ContainerConfig, name string
v.Set("name", name)
uri = fmt.Sprintf("%s?%s", uri, v.Encode())
}
- data, err = client.doRequest("POST", uri, data, nil)
+ headers := map[string]string{}
+ if auth != nil {
+ encoded_auth, err := auth.encode()
+ if err != nil {
+ return "", err
+ }
+ headers["X-Registry-Auth"] = encoded_auth
+ }
+ data, err = client.doRequest("POST", uri, data, headers)
if err != nil {
return "", err
}
result := &RespContainersCreate{}
err = json.Unmarshal(data, result)
if err != nil {
- return "", err
+ return "", fmt.Errorf(string(data))
}
return result.Id, nil
}
@@ -244,6 +265,36 @@ func (client *DockerClient) ContainerChanges(id string) ([]*ContainerChanges, er
return changes, nil
}
+func (client *DockerClient) ContainerStats(id string, stopChan <-chan struct{}) (<-chan StatsOrError, error) {
+ uri := fmt.Sprintf("/%s/containers/%s/stats", APIVersion, id)
+ resp, err := client.HTTPClient.Get(client.URL.String() + uri)
+ if err != nil {
+ return nil, err
+ }
+
+ decode := func(decoder *json.Decoder) decodingResult {
+ var containerStats Stats
+ if err := decoder.Decode(&containerStats); err != nil {
+ return decodingResult{err: err}
+ } else {
+ return decodingResult{result: containerStats}
+ }
+ }
+ decodingResultChan := client.readJSONStream(resp.Body, decode, stopChan)
+ statsOrErrorChan := make(chan StatsOrError)
+ go func() {
+ for decodingResult := range decodingResultChan {
+ stats, _ := decodingResult.result.(Stats)
+ statsOrErrorChan <- StatsOrError{
+ Stats: stats,
+ Error: decodingResult.err,
+ }
+ }
+ close(statsOrErrorChan)
+ }()
+ return statsOrErrorChan, nil
+}
+
func (client *DockerClient) readJSONStream(stream io.ReadCloser, decode func(*json.Decoder) decodingResult, stopChan <-chan struct{}) <-chan decodingResult {
resultChan := make(chan decodingResult)
@@ -335,6 +386,29 @@ func (client *DockerClient) ExecResize(id string, width, height int) error {
return nil
}
+func (client *DockerClient) AttachContainer(id string, options *AttachOptions) (io.ReadCloser, error) {
+ v := url.Values{}
+ if options != nil {
+ if options.Logs {
+ v.Set("logs", "1")
+ }
+ if options.Stream {
+ v.Set("stream", "1")
+ }
+ if options.Stdin {
+ v.Set("stdin", "1")
+ }
+ if options.Stdout {
+ v.Set("stdout", "1")
+ }
+ if options.Stderr {
+ v.Set("stderr", "1")
+ }
+ }
+ uri := fmt.Sprintf("/%s/containers/%s/attach?%s", APIVersion, id, v.Encode())
+ return client.doStreamRequest("POST", uri, nil, nil)
+}
+
func (client *DockerClient) StartContainer(id string, config *HostConfig) error {
data, err := json.Marshal(config)
if err != nil {
@@ -468,7 +542,7 @@ func (client *DockerClient) StartMonitorEvents(cb Callback, ec chan error, args
for e := range eventErrChan {
if e.Error != nil {
if ec != nil {
- ec <- err
+ ec <- e.Error
}
return
}
@@ -478,6 +552,9 @@ func (client *DockerClient) StartMonitorEvents(cb Callback, ec chan error, args
}
func (client *DockerClient) StopAllMonitorEvents() {
+ if client.eventStopChan == nil {
+ return
+ }
close(client.eventStopChan)
}
@@ -625,17 +702,9 @@ func (client *DockerClient) InspectImage(id string) (*ImageInfo, error) {
}
func (client *DockerClient) LoadImage(reader io.Reader) error {
- data, err := ioutil.ReadAll(reader)
- if err != nil {
- return err
- }
-
uri := fmt.Sprintf("/%s/images/load", APIVersion)
- _, err = client.doRequest("POST", uri, data, nil)
- if err != nil {
- return err
- }
- return nil
+ _, err := client.doStreamRequest("POST", uri, reader, nil)
+ return err
}
func (client *DockerClient) RemoveContainer(id string, force, volumes bool) error {
@@ -689,6 +758,31 @@ func (client *DockerClient) RemoveImage(name string, force bool) ([]*ImageDelete
return imageDelete, nil
}
+func (client *DockerClient) SearchImages(query, registry string, auth *AuthConfig) ([]ImageSearch, error) {
+ term := query
+ if registry != "" {
+ term = registry + "/" + term
+ }
+ uri := fmt.Sprintf("/%s/images/search?term=%s", APIVersion, term)
+ headers := map[string]string{}
+ if auth != nil {
+ if encodedAuth, err := auth.encode(); err != nil {
+ return nil, err
+ } else {
+ headers["X-Registry-Auth"] = encodedAuth
+ }
+ }
+ data, err := client.doRequest("GET", uri, nil, headers)
+ if err != nil {
+ return nil, err
+ }
+ var imageSearches []ImageSearch
+ if err := json.Unmarshal(data, &imageSearches); err != nil {
+ return nil, err
+ }
+ return imageSearches, nil
+}
+
func (client *DockerClient) PauseContainer(id string) error {
uri := fmt.Sprintf("/%s/containers/%s/pause", APIVersion, id)
_, err := client.doRequest("POST", uri, nil, nil)
@@ -890,8 +984,8 @@ func (client *DockerClient) ConnectNetwork(id, container string) error {
return err
}
-func (client *DockerClient) DisconnectNetwork(id, container string) error {
- data, err := json.Marshal(NetworkDisconnect{Container: container})
+func (client *DockerClient) DisconnectNetwork(id, container string, force bool) error {
+ data, err := json.Marshal(NetworkDisconnect{Container: container, Force: force})
if err != nil {
return err
}
diff --git a/go/src/github.com/samalba/dockerclient/dockerclient_test.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/dockerclient_test.go
old mode 100755
new mode 100644
similarity index 73%
rename from go/src/github.com/samalba/dockerclient/dockerclient_test.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/dockerclient_test.go
index afc1b071..7c7b3f59
--- a/go/src/github.com/samalba/dockerclient/dockerclient_test.go
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/dockerclient_test.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "os"
"reflect"
"strings"
"testing"
@@ -31,6 +32,40 @@ func testDockerClient(t *testing.T) *DockerClient {
return client
}
+func ExampleDockerClient_AttachContainer() {
+ docker, err := NewDockerClient("unix:///var/run/docker.sock", nil)
+ if err != nil {
+ panic(err)
+ }
+ cID, err := docker.CreateContainer(&ContainerConfig{
+ Cmd: []string{"echo", "hi"},
+ Image: "busybox",
+ }, "", nil)
+ if err != nil {
+ panic(err)
+ }
+ done := make(chan struct{})
+ if body, err := docker.AttachContainer(cID, &AttachOptions{
+ Stream: true,
+ Stdout: true,
+ }); err != nil {
+ panic(err)
+ } else {
+ go func() {
+ defer body.Close()
+ if _, err := stdcopy.StdCopy(os.Stdout, os.Stderr, body); err != nil {
+ panic(err)
+ }
+ close(done)
+ }()
+ }
+
+ if err := docker.StartContainer(cID, nil); err != nil {
+ panic(err)
+ }
+ <-done
+}
+
func TestInfo(t *testing.T) {
client := testDockerClient(t)
info, err := client.Info()
@@ -179,6 +214,50 @@ func TestContainerLogs(t *testing.T) {
}
}
+func TestContainerStats(t *testing.T) {
+ client := testDockerClient(t)
+ var expectedContainerStats Stats
+ if err := json.Unmarshal([]byte(statsResp), &expectedContainerStats); err != nil {
+ t.Fatalf("cannot parse expected resp: %s", err.Error())
+ }
+ containerIds := []string{"foobar", "foo"}
+ expectedResults := [][]StatsOrError{
+ {{Stats: expectedContainerStats}, {Error: fmt.Errorf("invalid character 'i' looking for beginning of value")}},
+ {{Stats: expectedContainerStats}, {Stats: expectedContainerStats}},
+ }
+
+ for i := range containerIds {
+ t.Logf("on outer iter %d\n", i)
+ stopChan := make(chan struct{})
+ statsOrErrorChan, err := client.ContainerStats(containerIds[i], stopChan)
+ if err != nil {
+ t.Fatalf("cannot get stats from server: %s", err.Error())
+ }
+
+ for j, expectedResult := range expectedResults[i] {
+ t.Logf("on iter %d\n", j)
+ containerStatsOrError := <-statsOrErrorChan
+ if containerStatsOrError.Error != nil {
+ if expectedResult.Error == nil {
+ t.Fatalf("index %d, got unexpected error %v", j, containerStatsOrError.Error)
+ } else if containerStatsOrError.Error.Error() == expectedResult.Error.Error() {
+ // continue so that we don't try to
+ // compare error values directly
+ continue
+ } else {
+ t.Fatalf("index %d, expected error %q but got %q", j, expectedResult.Error, containerStatsOrError.Error)
+ }
+ }
+ if !reflect.DeepEqual(containerStatsOrError, expectedResult) {
+ t.Fatalf("index %d, got:\n%#v\nexpected:\n%#v", j, containerStatsOrError, expectedResult)
+ }
+ t.Logf("done with iter %d\n", j)
+ }
+ close(stopChan)
+ t.Logf("done with outer iter %d\n", i)
+ }
+}
+
func TestMonitorEvents(t *testing.T) {
client := testDockerClient(t)
decoder := json.NewDecoder(bytes.NewBufferString(eventsResp))
diff --git a/go/src/github.com/samalba/dockerclient/engine_mock_test.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/engine_mock_test.go
old mode 100755
new mode 100644
similarity index 94%
rename from go/src/github.com/samalba/dockerclient/engine_mock_test.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/engine_mock_test.go
index 7d3a6d93..b2382a15
--- a/go/src/github.com/samalba/dockerclient/engine_mock_test.go
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/engine_mock_test.go
@@ -13,7 +13,6 @@ import (
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/jsonlog"
"github.com/docker/docker/pkg/stdcopy"
- "github.com/docker/docker/pkg/timeutils"
"github.com/gorilla/mux"
)
@@ -28,6 +27,7 @@ func init() {
r.HandleFunc(baseURL+"/containers/json", handlerGetContainers).Methods("GET")
r.HandleFunc(baseURL+"/containers/{id}/logs", handleContainerLogs).Methods("GET")
r.HandleFunc(baseURL+"/containers/{id}/changes", handleContainerChanges).Methods("GET")
+ r.HandleFunc(baseURL+"/containers/{id}/stats", handleContainerStats).Methods("GET")
r.HandleFunc(baseURL+"/containers/{id}/kill", handleContainerKill).Methods("POST")
r.HandleFunc(baseURL+"/containers/{id}/wait", handleWait).Methods("POST")
r.HandleFunc(baseURL+"/images/create", handleImagePull).Methods("POST")
@@ -109,7 +109,7 @@ func handleContainerLogs(w http.ResponseWriter, r *http.Request) {
line := fmt.Sprintf("line %d", i)
if getBoolValue(r.Form.Get("timestamps")) {
l := &jsonlog.JSONLog{Log: line, Created: time.Now().UTC()}
- line = fmt.Sprintf("%s %s", l.Created.Format(timeutils.RFC3339NanoFixed), line)
+ line = fmt.Sprintf("%s %s", l.Created.Format(jsonlog.RFC3339NanoFixed), line)
}
if i%2 == 0 && stderr {
fmt.Fprintln(errStream, line)
@@ -138,6 +138,15 @@ func handleContainerChanges(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(body))
}
+func handleContainerStats(w http.ResponseWriter, r *http.Request) {
+ switch mux.Vars(r)["id"] {
+ case "foobar":
+ fmt.Fprintf(w, "%s invalidresp", statsResp)
+ default:
+ fmt.Fprintf(w, "%s %s", statsResp, statsResp)
+ }
+}
+
func getBoolValue(boolString string) bool {
switch boolString {
case "1":
diff --git a/go/src/github.com/samalba/dockerclient/example_responses.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/example_responses.go
old mode 100755
new mode 100644
similarity index 66%
rename from go/src/github.com/samalba/dockerclient/example_responses.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/example_responses.go
index 670508c0..e4c890dc
--- a/go/src/github.com/samalba/dockerclient/example_responses.go
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/example_responses.go
@@ -10,4 +10,6 @@ var haproxyPullOutput = `{"status":"The image you are pulling has been verified"
{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"ecb4b23ca7ce"}{"status":"Already exists","progressDetail":{},"id":"f453e940c177"}{"status":"Already exists","progressDetail":{},"id":"fc5ea1bc05ab"}{"status":"Already exists","progressDetail":{},"id":"380557f8f7b3"}{"status":"Status: Image is up to date for haproxy"}
`
+var statsResp = `{"read":"2015-02-02T17:06:08.187833376-05:00","network":{"rx_bytes":99988,"rx_packets":928,"rx_errors":0,"rx_dropped":0,"tx_bytes":1786548,"tx_packets":877,"tx_errors":0,"tx_dropped":0},"cpu_stats":{"cpu_usage":{"total_usage":170018598,"percpu_usage":[170018598],"usage_in_kernelmode":30000000,"usage_in_usermode":70000000},"system_cpu_usage":9020930000000,"throttling_data":{"periods":0,"throttled_periods":0,"throttled_time":0}},"memory_stats":{"usage":18022400,"max_usage":20541440,"stats":{"active_anon":6213632,"active_file":176128,"cache":11808768,"hierarchical_memory_limit":9223372036854775807,"hierarchical_memsw_limit":9223372036854775807,"inactive_anon":0,"inactive_file":11632640,"mapped_file":5165056,"pgfault":2535,"pgmajfault":13,"pgpgin":4293,"pgpgout":1937,"rss":6213632,"rss_huge":2097152,"swap":0,"total_active_anon":6213632,"total_active_file":176128,"total_cache":11808768,"total_inactive_anon":0,"total_inactive_file":11632640,"total_mapped_file":5165056,"total_pgfault":2535,"total_pgmajfault":13,"total_pgpgin":4293,"total_pgpgout":1937,"total_rss":6213632,"total_rss_huge":2097152,"total_swap":0,"total_unevictable":0,"unevictable":0},"failcnt":0,"limit":1041051648},"blkio_stats":{"io_service_bytes_recursive":[{"major":7,"minor":0,"op":"Read","value":28672},{"major":7,"minor":0,"op":"Write","value":0},{"major":7,"minor":0,"op":"Sync","value":0},{"major":7,"minor":0,"op":"Async","value":28672},{"major":7,"minor":0,"op":"Total","value":28672},{"major":253,"minor":0,"op":"Read","value":28672},{"major":253,"minor":0,"op":"Write","value":0},{"major":253,"minor":0,"op":"Sync","value":0},{"major":253,"minor":0,"op":"Async","value":28672},{"major":253,"minor":0,"op":"Total","value":28672},{"major":253,"minor":7,"op":"Read","value":11718656},{"major":253,"minor":7,"op":"Write","value":0},{"major":253,"minor":7,"op":"Sync","value":0},{"major":253,"minor":7,"op":"Async","value":11718656},{"major":253,"minor":7,"op":"Total","value":11718656},{"major":202,"minor":0,"op":"Read","value":0},{"major":202,"minor":0,"op":"Write","value":0},{"major":202,"minor":0,"op":"Sync","value":0},{"major":202,"minor":0,"op":"Async","value":0},{"major":202,"minor":0,"op":"Total","value":0}],"io_serviced_recursive":[{"major":7,"minor":0,"op":"Read","value":7},{"major":7,"minor":0,"op":"Write","value":0},{"major":7,"minor":0,"op":"Sync","value":0},{"major":7,"minor":0,"op":"Async","value":7},{"major":7,"minor":0,"op":"Total","value":7},{"major":253,"minor":0,"op":"Read","value":7},{"major":253,"minor":0,"op":"Write","value":0},{"major":253,"minor":0,"op":"Sync","value":0},{"major":253,"minor":0,"op":"Async","value":7},{"major":253,"minor":0,"op":"Total","value":7},{"major":253,"minor":7,"op":"Read","value":312},{"major":253,"minor":7,"op":"Write","value":0},{"major":253,"minor":7,"op":"Sync","value":0},{"major":253,"minor":7,"op":"Async","value":312},{"major":253,"minor":7,"op":"Total","value":312},{"major":202,"minor":0,"op":"Read","value":0},{"major":202,"minor":0,"op":"Write","value":0},{"major":202,"minor":0,"op":"Sync","value":0},{"major":202,"minor":0,"op":"Async","value":0},{"major":202,"minor":0,"op":"Total","value":0}],"io_queue_recursive":[],"io_service_time_recursive":[],"io_wait_time_recursive":[],"io_merged_recursive":[],"io_time_recursive":[],"sectors_recursive":[]}}`
+
var eventsResp = `{"status":"pull","id":"nginx:latest","time":1428620433}{"status":"create","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620433}{"status":"start","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620433}{"status":"die","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620442}{"status":"create","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"start","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"die","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"pull","id":"debian:latest","time":1428620453}{"status":"create","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"start","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"die","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"create","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620458}{"status":"start","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620458}{"status":"pause","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620462}{"status":"unpause","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620466}{"status":"die","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620469}`
diff --git a/go/src/github.com/samalba/dockerclient/examples/events.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/examples/events.go
old mode 100755
new mode 100644
similarity index 100%
rename from go/src/github.com/samalba/dockerclient/examples/events.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/examples/events.go
diff --git a/go/src/github.com/samalba/dockerclient/examples/stats/stats.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/examples/stats/stats.go
old mode 100755
new mode 100644
similarity index 92%
rename from go/src/github.com/samalba/dockerclient/examples/stats/stats.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/examples/stats/stats.go
index 9027069d..81ee2fb4
--- a/go/src/github.com/samalba/dockerclient/examples/stats/stats.go
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/examples/stats/stats.go
@@ -27,7 +27,7 @@ func main() {
}
containerConfig := &dockerclient.ContainerConfig{Image: "busybox", Cmd: []string{"sh"}}
- containerId, err := docker.CreateContainer(containerConfig, "")
+ containerId, err := docker.CreateContainer(containerConfig, "", nil)
if err != nil {
log.Fatal(err)
}
diff --git a/go/src/github.com/samalba/dockerclient/interface.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/interface.go
old mode 100755
new mode 100644
similarity index 78%
rename from go/src/github.com/samalba/dockerclient/interface.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/interface.go
index cb7a8b79..b373055e
--- a/go/src/github.com/samalba/dockerclient/interface.go
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/interface.go
@@ -13,13 +13,20 @@ type Client interface {
ListContainers(all, size bool, filters string) ([]Container, error)
InspectContainer(id string) (*ContainerInfo, error)
InspectImage(id string) (*ImageInfo, error)
- CreateContainer(config *ContainerConfig, name string) (string, error)
+ CreateContainer(config *ContainerConfig, name string, authConfig *AuthConfig) (string, error)
ContainerLogs(id string, options *LogOptions) (io.ReadCloser, error)
ContainerChanges(id string) ([]*ContainerChanges, error)
+ // ContainerStats takes a container ID and an optional stop channel and
+ // returns a StatsOrError channel. If an error is ever sent, then no
+ // more stats will be sent on that channel. If a stop channel is
+ // provided, events will stop being monitored after the stop channel is
+ // closed.
+ ContainerStats(id string, stopChan <-chan struct{}) (<-chan StatsOrError, error)
ExecCreate(config *ExecConfig) (string, error)
ExecStart(id string, config *ExecConfig) error
ExecResize(id string, width, height int) error
StartContainer(id string, config *HostConfig) error
+ AttachContainer(id string, options *AttachOptions) (io.ReadCloser, error)
StopContainer(id string, timeout int) error
RestartContainer(id string, timeout int) error
KillContainer(id, signal string) error
@@ -41,6 +48,7 @@ type Client interface {
RemoveContainer(id string, force, volumes bool) error
ListImages(all bool) ([]*Image, error)
RemoveImage(name string, force bool) ([]*ImageDelete, error)
+ SearchImages(query, registry string, auth *AuthConfig) ([]ImageSearch, error)
PauseContainer(name string) error
UnpauseContainer(name string) error
RenameContainer(oldName string, newName string) error
@@ -53,6 +61,6 @@ type Client interface {
InspectNetwork(id string) (*NetworkResource, error)
CreateNetwork(config *NetworkCreate) (*NetworkCreateResponse, error)
ConnectNetwork(id, container string) error
- DisconnectNetwork(id, container string) error
+ DisconnectNetwork(id, container string, force bool) error
RemoveNetwork(id string) error
}
diff --git a/go/src/github.com/samalba/dockerclient/mockclient/mock.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/mockclient/mock.go
old mode 100755
new mode 100644
similarity index 88%
rename from go/src/github.com/samalba/dockerclient/mockclient/mock.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/mockclient/mock.go
index a54ee575..9da36b87
--- a/go/src/github.com/samalba/dockerclient/mockclient/mock.go
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/mockclient/mock.go
@@ -35,8 +35,8 @@ func (client *MockClient) InspectImage(id string) (*dockerclient.ImageInfo, erro
return args.Get(0).(*dockerclient.ImageInfo), args.Error(1)
}
-func (client *MockClient) CreateContainer(config *dockerclient.ContainerConfig, name string) (string, error) {
- args := client.Mock.Called(config, name)
+func (client *MockClient) CreateContainer(config *dockerclient.ContainerConfig, name string, authConfig *dockerclient.AuthConfig) (string, error) {
+ args := client.Mock.Called(config, name, authConfig)
return args.String(0), args.Error(1)
}
@@ -50,6 +50,16 @@ func (client *MockClient) ContainerChanges(id string) ([]*dockerclient.Container
return args.Get(0).([]*dockerclient.ContainerChanges), args.Error(1)
}
+func (client *MockClient) ContainerStats(id string, stopChan <-chan struct{}) (<-chan dockerclient.StatsOrError, error) {
+ args := client.Mock.Called(id, stopChan)
+ return args.Get(0).(<-chan dockerclient.StatsOrError), args.Error(1)
+}
+
+func (client *MockClient) AttachContainer(id string, options *dockerclient.AttachOptions) (io.ReadCloser, error) {
+ args := client.Mock.Called(id, options)
+ return args.Get(0).(io.ReadCloser), args.Error(1)
+}
+
func (client *MockClient) StartContainer(id string, config *dockerclient.HostConfig) error {
args := client.Mock.Called(id, config)
return args.Error(0)
@@ -136,6 +146,11 @@ func (client *MockClient) RemoveImage(name string, force bool) ([]*dockerclient.
return args.Get(0).([]*dockerclient.ImageDelete), args.Error(1)
}
+func (client *MockClient) SearchImages(query, registry string, authConfig *dockerclient.AuthConfig) ([]dockerclient.ImageSearch, error) {
+ args := client.Mock.Called(query, registry, authConfig)
+ return args.Get(0).([]dockerclient.ImageSearch), args.Error(1)
+}
+
func (client *MockClient) PauseContainer(name string) error {
args := client.Mock.Called(name)
return args.Error(0)
@@ -211,8 +226,8 @@ func (client *MockClient) ConnectNetwork(id, container string) error {
return args.Error(0)
}
-func (client *MockClient) DisconnectNetwork(id, container string) error {
- args := client.Mock.Called(id, container)
+func (client *MockClient) DisconnectNetwork(id, container string, force bool) error {
+ args := client.Mock.Called(id, container, force)
return args.Error(0)
}
diff --git a/go/src/github.com/samalba/dockerclient/mockclient/mock_test.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/mockclient/mock_test.go
old mode 100755
new mode 100644
similarity index 100%
rename from go/src/github.com/samalba/dockerclient/mockclient/mock_test.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/mockclient/mock_test.go
diff --git a/go/src/github.com/samalba/dockerclient/nopclient/nop.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/nopclient/nop.go
old mode 100755
new mode 100644
similarity index 88%
rename from go/src/github.com/samalba/dockerclient/nopclient/nop.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/nopclient/nop.go
index 03dfbab1..659b57b7
--- a/go/src/github.com/samalba/dockerclient/nopclient/nop.go
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/nopclient/nop.go
@@ -34,7 +34,7 @@ func (client *NopClient) InspectImage(id string) (*dockerclient.ImageInfo, error
return nil, ErrNoEngine
}
-func (client *NopClient) CreateContainer(config *dockerclient.ContainerConfig, name string) (string, error) {
+func (client *NopClient) CreateContainer(config *dockerclient.ContainerConfig, name string, authConfig *dockerclient.AuthConfig) (string, error) {
return "", ErrNoEngine
}
@@ -46,6 +46,14 @@ func (client *NopClient) ContainerChanges(id string) ([]*dockerclient.ContainerC
return nil, ErrNoEngine
}
+func (client *NopClient) ContainerStats(id string, stopChan <-chan struct{}) (<-chan dockerclient.StatsOrError, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) AttachContainer(id string, options *dockerclient.AttachOptions) (io.ReadCloser, error) {
+ return nil, ErrNoEngine
+}
+
func (client *NopClient) StartContainer(id string, config *dockerclient.HostConfig) error {
return ErrNoEngine
}
@@ -118,6 +126,10 @@ func (client *NopClient) RemoveImage(name string, force bool) ([]*dockerclient.I
return nil, ErrNoEngine
}
+func (client *NopClient) SearchImages(query, registry string, authConfig *dockerclient.AuthConfig) ([]dockerclient.ImageSearch, error) {
+ return nil, ErrNoEngine
+}
+
func (client *NopClient) PauseContainer(name string) error {
return ErrNoEngine
}
@@ -178,7 +190,7 @@ func (client *NopClient) ConnectNetwork(id, container string) error {
return ErrNoEngine
}
-func (client *NopClient) DisconnectNetwork(id, container string) error {
+func (client *NopClient) DisconnectNetwork(id, container string, force bool) error {
return ErrNoEngine
}
diff --git a/go/src/goproxy/vendor/github.com/samalba/dockerclient/tls.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/tls.go
new file mode 100644
index 00000000..80ae6f1e
--- /dev/null
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/tls.go
@@ -0,0 +1,38 @@
+package dockerclient
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "errors"
+ "io/ioutil"
+ "path/filepath"
+)
+
+// TLSConfigFromCertPath returns a configuration based on PEM files in the directory
+//
+// path is usually what is set by the environment variable `DOCKER_CERT_PATH`,
+// or `$HOME/.docker`.
+func TLSConfigFromCertPath(path string) (*tls.Config, error) {
+ cert, err := ioutil.ReadFile(filepath.Join(path, "cert.pem"))
+ if err != nil {
+ return nil, err
+ }
+ key, err := ioutil.ReadFile(filepath.Join(path, "key.pem"))
+ if err != nil {
+ return nil, err
+ }
+ ca, err := ioutil.ReadFile(filepath.Join(path, "ca.pem"))
+ if err != nil {
+ return nil, err
+ }
+ tlsCert, err := tls.X509KeyPair(cert, key)
+ if err != nil {
+ return nil, err
+ }
+ tlsConfig := &tls.Config{Certificates: []tls.Certificate{tlsCert}}
+ tlsConfig.RootCAs = x509.NewCertPool()
+ if !tlsConfig.RootCAs.AppendCertsFromPEM(ca) {
+ return nil, errors.New("Could not add RootCA pem")
+ }
+ return tlsConfig, nil
+}
diff --git a/go/src/github.com/samalba/dockerclient/types.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/types.go
old mode 100755
new mode 100644
similarity index 72%
rename from go/src/github.com/samalba/dockerclient/types.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/types.go
index 7b64c89d..7ba79915
--- a/go/src/github.com/samalba/dockerclient/types.go
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/types.go
@@ -5,7 +5,7 @@ import (
"io"
"time"
- "github.com/docker/docker/pkg/units"
+ "github.com/docker/go-units"
)
type ContainerConfig struct {
@@ -43,49 +43,70 @@ type ContainerConfig struct {
// This is used only by the create command
HostConfig HostConfig
+
+ // Network configuration support
+ NetworkingConfig NetworkingConfig
}
type HostConfig struct {
- Binds []string
- ContainerIDFile string
- LxcConf []map[string]string
- Memory int64
- MemoryReservation int64
- MemorySwap int64
- KernelMemory int64
- CpuShares int64
- CpuPeriod int64
- CpusetCpus string
- CpusetMems string
- CpuQuota int64
- BlkioWeight int64
- OomKillDisable bool
- MemorySwappiness int64
- Privileged bool
- PortBindings map[string][]PortBinding
- Links []string
- PublishAllPorts bool
- Dns []string
- DNSOptions []string
- DnsSearch []string
- ExtraHosts []string
- VolumesFrom []string
- Devices []DeviceMapping
- NetworkMode string
- IpcMode string
- PidMode string
- UTSMode string
- CapAdd []string
- CapDrop []string
- GroupAdd []string
- RestartPolicy RestartPolicy
- SecurityOpt []string
- ReadonlyRootfs bool
- Ulimits []Ulimit
- LogConfig LogConfig
- CgroupParent string
- ConsoleSize [2]int
- VolumeDriver string
+ Binds []string
+ ContainerIDFile string
+ LxcConf []map[string]string
+ Memory int64
+ MemoryReservation int64
+ MemorySwap int64
+ KernelMemory int64
+ CpuShares int64
+ CpuPeriod int64
+ CpusetCpus string
+ CpusetMems string
+ CpuQuota int64
+ BlkioWeight int64
+ OomKillDisable bool
+ MemorySwappiness int64
+ Privileged bool
+ PortBindings map[string][]PortBinding
+ Links []string
+ PublishAllPorts bool
+ Dns []string
+ DNSOptions []string
+ DnsSearch []string
+ ExtraHosts []string
+ VolumesFrom []string
+ Devices []DeviceMapping
+ NetworkMode string
+ IpcMode string
+ PidMode string
+ UTSMode string
+ CapAdd []string
+ CapDrop []string
+ GroupAdd []string
+ RestartPolicy RestartPolicy
+ SecurityOpt []string
+ ReadonlyRootfs bool
+ Ulimits []Ulimit
+ LogConfig LogConfig
+ CgroupParent string
+ ConsoleSize [2]int
+ VolumeDriver string
+ OomScoreAdj int
+ Tmpfs map[string]string
+ ShmSize int64
+ BlkioWeightDevice []WeightDevice
+ BlkioDeviceReadBps []ThrottleDevice
+ BlkioDeviceWriteBps []ThrottleDevice
+ BlkioDeviceReadIOps []ThrottleDevice
+ BlkioDeviceWriteIOps []ThrottleDevice
+}
+
+type WeightDevice struct {
+ Path string
+ Weight uint16
+}
+
+type ThrottleDevice struct {
+ Path string
+ Rate uint64
}
type DeviceMapping struct {
@@ -112,6 +133,14 @@ type LogOptions struct {
Tail int64
}
+type AttachOptions struct {
+ Logs bool
+ Stream bool
+ Stdin bool
+ Stdout bool
+ Stderr bool
+}
+
type MonitorEventsFilters struct {
Event string `json:",omitempty"`
Image string `json:",omitempty"`
@@ -209,6 +238,14 @@ type ImageInfo struct {
VirtualSize int64
}
+type ImageSearch struct {
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ IsOfficial bool `json:"is_official,omitempty" yaml:"is_official,omitempty"`
+ IsAutomated bool `json:"is_automated,omitempty" yaml:"is_automated,omitempty"`
+ Name string `json:"name,omitempty" yaml:"name,omitempty"`
+ StarCount int `json:"star_count,omitempty" yaml:"star_count,omitempty"`
+}
+
type ContainerInfo struct {
Id string
Created string
@@ -225,6 +262,7 @@ type ContainerInfo struct {
Gateway string
Bridge string
Ports map[string][]PortBinding
+ Networks map[string]*EndpointSettings
}
SysInitPath string
ResolvConfPath string
@@ -244,24 +282,62 @@ type Port struct {
Type string
}
+// EndpointSettings stores the network endpoint details
+type EndpointSettings struct {
+ // Configurations
+ IPAMConfig *EndpointIPAMConfig
+ Links []string
+ Aliases []string
+ // Operational data
+ NetworkID string
+ EndpointID string
+ Gateway string
+ IPAddress string
+ IPPrefixLen int
+ IPv6Gateway string
+ GlobalIPv6Address string
+ GlobalIPv6PrefixLen int
+ MacAddress string
+}
+
+// NetworkingConfig represents the container's networking configuration for each of its interfaces
+// Carries the networink configs specified in the `docker run` and `docker network connect` commands
+type NetworkingConfig struct {
+ EndpointsConfig map[string]*EndpointSettings // Endpoint configs for each conencting network
+}
+
type Container struct {
- Id string
- Names []string
- Image string
- Command string
- Created int64
- Status string
- Ports []Port
- SizeRw int64
- SizeRootFs int64
- Labels map[string]string
+ Id string
+ Names []string
+ Image string
+ Command string
+ Created int64
+ Status string
+ Ports []Port
+ SizeRw int64
+ SizeRootFs int64
+ Labels map[string]string
+ NetworkSettings struct {
+ Networks map[string]EndpointSettings
+ }
+}
+
+type Actor struct {
+ ID string
+ Attributes map[string]string
}
type Event struct {
- Id string
- Status string
- From string
- Time int64
+ Status string `json:"status,omitempty"`
+ ID string `json:"id,omitempty"`
+ From string `json:"from,omitempty"`
+
+ Type string
+ Action string
+ Actor Actor
+
+ Time int64 `json:"time,omitempty"`
+ TimeNano int64 `json:"timeNano,omitempty"`
}
type Version struct {
@@ -331,6 +407,11 @@ type ImageDelete struct {
Untagged string
}
+type StatsOrError struct {
+ Stats
+ Error error
+}
+
type EventOrError struct {
Event
Error error
@@ -356,6 +437,7 @@ type ThrottlingData struct {
ThrottledTime uint64 `json:"throttled_time"`
}
+// All CPU stats are aggregated since container inception.
type CpuUsage struct {
// Total CPU time consumed.
// Units: nanoseconds.
@@ -474,8 +556,9 @@ type VolumeCreateRequest struct {
// IPAM represents IP Address Management
type IPAM struct {
- Driver string
- Config []IPAMConfig
+ Driver string
+ Options map[string]string //Per network IPAM driver options
+ Config []IPAMConfig
}
// IPAMConfig represents IPAM configurations
@@ -486,18 +569,27 @@ type IPAMConfig struct {
AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
}
+// EndpointIPAMConfig represents IPAM configurations for the endpoint
+type EndpointIPAMConfig struct {
+ IPv4Address string `json:",omitempty"`
+ IPv6Address string `json:",omitempty"`
+}
+
// NetworkResource is the body of the "get network" http response message
type NetworkResource struct {
- Name string
- ID string `json:"Id"`
- Scope string
- Driver string
- IPAM IPAM
+ Name string
+ ID string `json:"Id"`
+ Scope string
+ Driver string
+ IPAM IPAM
+ //Internal bool
Containers map[string]EndpointResource
+ Options map[string]string
}
-//EndpointResource contains network resources allocated and usd for a container in a network
+// EndpointResource contains network resources allocated and used for a container in a network
type EndpointResource struct {
+ Name string
EndpointID string
MacAddress string
IPv4Address string
@@ -510,6 +602,8 @@ type NetworkCreate struct {
CheckDuplicate bool
Driver string
IPAM IPAM
+ Internal bool
+ Options map[string]string
}
// NetworkCreateResponse is the response message sent by the server for network create call
@@ -526,4 +620,5 @@ type NetworkConnect struct {
// NetworkDisconnect represents the data to be used to disconnect a container from the network
type NetworkDisconnect struct {
Container string
+ Force bool
}
diff --git a/go/src/github.com/samalba/dockerclient/utils.go b/go/src/goproxy/vendor/github.com/samalba/dockerclient/utils.go
old mode 100755
new mode 100644
similarity index 62%
rename from go/src/github.com/samalba/dockerclient/utils.go
rename to go/src/goproxy/vendor/github.com/samalba/dockerclient/utils.go
index 806f1b3e..8a6b0d6e
--- a/go/src/github.com/samalba/dockerclient/utils.go
+++ b/go/src/goproxy/vendor/github.com/samalba/dockerclient/utils.go
@@ -8,7 +8,9 @@ import (
"time"
)
-func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration) *http.Client {
+type tcpFunc func(*net.TCPConn, time.Duration) error
+
+func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration, setUserTimeout tcpFunc) *http.Client {
httpTransport := &http.Transport{
TLSClientConfig: tlsConfig,
}
@@ -16,7 +18,13 @@ func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration) *ht
switch u.Scheme {
default:
httpTransport.Dial = func(proto, addr string) (net.Conn, error) {
- return net.DialTimeout(proto, addr, timeout)
+ conn, err := net.DialTimeout(proto, addr, timeout)
+ if tcpConn, ok := conn.(*net.TCPConn); ok && setUserTimeout != nil {
+ // Sender can break TCP connection if the remote side doesn't
+ // acknowledge packets within timeout
+ setUserTimeout(tcpConn, timeout)
+ }
+ return conn, err
}
case "unix":
socketPath := u.Path
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/.travis.yml b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/.travis.yml
new file mode 100644
index 00000000..ff23150d
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+go:
+ - 1.3
+ - 1.4
+ - 1.5
+ - tip
+install:
+ - go get -t ./...
+script: GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./...
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/CHANGELOG.md b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/CHANGELOG.md
new file mode 100644
index 00000000..9e9e6009
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/CHANGELOG.md
@@ -0,0 +1,59 @@
+# 0.9.0
+
+* logrus/text_formatter: don't emit empty msg
+* logrus/hooks/airbrake: move out of main repository
+* logrus/hooks/sentry: move out of main repository
+* logrus/hooks/papertrail: move out of main repository
+* logrus/hooks/bugsnag: move out of main repository
+* logrus/core: run tests with `-race`
+* logrus/core: detect TTY based on `stderr`
+* logrus/core: support `WithError` on logger
+* logrus/core: Solaris support
+
+# 0.8.7
+
+* logrus/core: fix possible race (#216)
+* logrus/doc: small typo fixes and doc improvements
+
+
+# 0.8.6
+
+* hooks/raven: allow passing an initialized client
+
+# 0.8.5
+
+* logrus/core: revert #208
+
+# 0.8.4
+
+* formatter/text: fix data race (#218)
+
+# 0.8.3
+
+* logrus/core: fix entry log level (#208)
+* logrus/core: improve performance of text formatter by 40%
+* logrus/core: expose `LevelHooks` type
+* logrus/core: add support for DragonflyBSD and NetBSD
+* formatter/text: print structs more verbosely
+
+# 0.8.2
+
+* logrus: fix more Fatal family functions
+
+# 0.8.1
+
+* logrus: fix not exiting on `Fatalf` and `Fatalln`
+
+# 0.8.0
+
+* logrus: defaults to stderr instead of stdout
+* hooks/sentry: add special field for `*http.Request`
+* formatter/text: ignore Windows for colors
+
+# 0.7.3
+
+* formatter/\*: allow configuration of timestamp layout
+
+# 0.7.2
+
+* formatter/text: Add configuration option for time format (#158)
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/LICENSE b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/LICENSE
new file mode 100644
index 00000000..f090cb42
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Simon Eskildsen
+
+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/go/src/gosetup/vendor/github.com/Sirupsen/logrus/README.md b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/README.md
new file mode 100644
index 00000000..d3a1d4cf
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/README.md
@@ -0,0 +1,385 @@
+# Logrus
[](https://travis-ci.org/Sirupsen/logrus) [](https://godoc.org/github.com/Sirupsen/logrus)
+
+Logrus is a structured logger for Go (golang), completely API compatible with
+the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
+yet stable (pre 1.0). Logrus itself is completely stable and has been used in
+many large deployments. The core API is unlikely to change much but please
+version control your Logrus to make sure you aren't fetching latest `master` on
+every build.**
+
+Nicely color-coded in development (when a TTY is attached, otherwise just
+plain text):
+
+
+
+With `log.Formatter = new(logrus.JSONFormatter)`, for easy parsing by logstash
+or Splunk:
+
+```json
+{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
+ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
+
+{"level":"warning","msg":"The group's number increased tremendously!",
+"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
+
+{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
+"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
+
+{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
+"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
+
+{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
+"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
+```
+
+With the default `log.Formatter = new(&log.TextFormatter{})` when a TTY is not
+attached, the output is compatible with the
+[logfmt](http://godoc.org/github.com/kr/logfmt) format:
+
+```text
+time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
+time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
+time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
+time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
+time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
+time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
+exit status 1
+```
+
+#### Example
+
+The simplest way to use Logrus is simply the package-level exported logger:
+
+```go
+package main
+
+import (
+ log "github.com/Sirupsen/logrus"
+)
+
+func main() {
+ log.WithFields(log.Fields{
+ "animal": "walrus",
+ }).Info("A walrus appears")
+}
+```
+
+Note that it's completely api-compatible with the stdlib logger, so you can
+replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
+and you'll now have the flexibility of Logrus. You can customize it all you
+want:
+
+```go
+package main
+
+import (
+ "os"
+ log "github.com/Sirupsen/logrus"
+)
+
+func init() {
+ // Log as JSON instead of the default ASCII formatter.
+ log.SetFormatter(&log.JSONFormatter{})
+
+ // Output to stderr instead of stdout, could also be a file.
+ log.SetOutput(os.Stderr)
+
+ // Only log the warning severity or above.
+ log.SetLevel(log.WarnLevel)
+}
+
+func main() {
+ log.WithFields(log.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+
+ log.WithFields(log.Fields{
+ "omg": true,
+ "number": 122,
+ }).Warn("The group's number increased tremendously!")
+
+ log.WithFields(log.Fields{
+ "omg": true,
+ "number": 100,
+ }).Fatal("The ice breaks!")
+
+ // A common pattern is to re-use fields between logging statements by re-using
+ // the logrus.Entry returned from WithFields()
+ contextLogger := log.WithFields(log.Fields{
+ "common": "this is a common field",
+ "other": "I also should be logged always",
+ })
+
+ contextLogger.Info("I'll be logged with common and other field")
+ contextLogger.Info("Me too")
+}
+```
+
+For more advanced usage such as logging to multiple locations from the same
+application, you can also create an instance of the `logrus` Logger:
+
+```go
+package main
+
+import (
+ "github.com/Sirupsen/logrus"
+)
+
+// Create a new instance of the logger. You can have any number of instances.
+var log = logrus.New()
+
+func main() {
+ // The API for setting attributes is a little different than the package level
+ // exported logger. See Godoc.
+ log.Out = os.Stderr
+
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+}
+```
+
+#### Fields
+
+Logrus encourages careful, structured logging though logging fields instead of
+long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
+to send event %s to topic %s with key %d")`, you should log the much more
+discoverable:
+
+```go
+log.WithFields(log.Fields{
+ "event": event,
+ "topic": topic,
+ "key": key,
+}).Fatal("Failed to send event")
+```
+
+We've found this API forces you to think about logging in a way that produces
+much more useful logging messages. We've been in countless situations where just
+a single added field to a log statement that was already there would've saved us
+hours. The `WithFields` call is optional.
+
+In general, with Logrus using any of the `printf`-family functions should be
+seen as a hint you should add a field, however, you can still use the
+`printf`-family functions with Logrus.
+
+#### Hooks
+
+You can add hooks for logging levels. For example to send errors to an exception
+tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
+multiple places simultaneously, e.g. syslog.
+
+Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
+`init`:
+
+```go
+import (
+ log "github.com/Sirupsen/logrus"
+ "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
+ "log/syslog"
+)
+
+func init() {
+
+ // Use the Airbrake hook to report errors that have Error severity or above to
+ // an exception tracker. You can create custom hooks, see the Hooks section.
+ log.AddHook(airbrake.NewHook(123, "xyz", "production"))
+
+ hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+ if err != nil {
+ log.Error("Unable to connect to local syslog daemon")
+ } else {
+ log.AddHook(hook)
+ }
+}
+```
+Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
+
+| Hook | Description |
+| ----- | ----------- |
+| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
+| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
+| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
+| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
+| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
+| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
+| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
+| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
+| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
+| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
+| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
+| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
+| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
+| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
+| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
+| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
+| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
+| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
+| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
+| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
+| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
+| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
+| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
+| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
+
+#### Level logging
+
+Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
+
+```go
+log.Debug("Useful debugging information.")
+log.Info("Something noteworthy happened!")
+log.Warn("You should probably take a look at this.")
+log.Error("Something failed but I'm not quitting.")
+// Calls os.Exit(1) after logging
+log.Fatal("Bye.")
+// Calls panic() after logging
+log.Panic("I'm bailing.")
+```
+
+You can set the logging level on a `Logger`, then it will only log entries with
+that severity or anything above it:
+
+```go
+// Will log anything that is info or above (warn, error, fatal, panic). Default.
+log.SetLevel(log.InfoLevel)
+```
+
+It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
+environment if your application has that.
+
+#### Entries
+
+Besides the fields added with `WithField` or `WithFields` some fields are
+automatically added to all logging events:
+
+1. `time`. The timestamp when the entry was created.
+2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
+ the `AddFields` call. E.g. `Failed to send event.`
+3. `level`. The logging level. E.g. `info`.
+
+#### Environments
+
+Logrus has no notion of environment.
+
+If you wish for hooks and formatters to only be used in specific environments,
+you should handle that yourself. For example, if your application has a global
+variable `Environment`, which is a string representation of the environment you
+could do:
+
+```go
+import (
+ log "github.com/Sirupsen/logrus"
+)
+
+init() {
+ // do something here to set environment depending on an environment variable
+ // or command-line flag
+ if Environment == "production" {
+ log.SetFormatter(&log.JSONFormatter{})
+ } else {
+ // The TextFormatter is default, you don't actually have to do this.
+ log.SetFormatter(&log.TextFormatter{})
+ }
+}
+```
+
+This configuration is how `logrus` was intended to be used, but JSON in
+production is mostly only useful if you do log aggregation with tools like
+Splunk or Logstash.
+
+#### Formatters
+
+The built-in logging formatters are:
+
+* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
+ without colors.
+ * *Note:* to force colored output when there is no TTY, set the `ForceColors`
+ field to `true`. To force no colored output even if there is a TTY set the
+ `DisableColors` field to `true`
+* `logrus.JSONFormatter`. Logs fields as JSON.
+* `logrus/formatters/logstash.LogstashFormatter`. Logs fields as [Logstash](http://logstash.net) Events.
+
+ ```go
+ logrus.SetFormatter(&logstash.LogstashFormatter{Type: "application_name"})
+ ```
+
+Third party logging formatters:
+
+* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
+* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
+
+You can define your formatter by implementing the `Formatter` interface,
+requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
+`Fields` type (`map[string]interface{}`) with all your fields as well as the
+default ones (see Entries section above):
+
+```go
+type MyJSONFormatter struct {
+}
+
+log.SetFormatter(new(MyJSONFormatter))
+
+func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
+ // Note this doesn't include Time, Level and Message which are available on
+ // the Entry. Consult `godoc` on information about those fields or read the
+ // source of the official loggers.
+ serialized, err := json.Marshal(entry.Data)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+ }
+ return append(serialized, '\n'), nil
+}
+```
+
+#### Logger as an `io.Writer`
+
+Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
+
+```go
+w := logger.Writer()
+defer w.Close()
+
+srv := http.Server{
+ // create a stdlib log.Logger that writes to
+ // logrus.Logger.
+ ErrorLog: log.New(w, "", 0),
+}
+```
+
+Each line written to that writer will be printed the usual way, using formatters
+and hooks. The level for those entries is `info`.
+
+#### Rotation
+
+Log rotation is not provided with Logrus. Log rotation should be done by an
+external program (like `logrotate(8)`) that can compress and delete old log
+entries. It should not be a feature of the application-level logger.
+
+#### Tools
+
+| Tool | Description |
+| ---- | ----------- |
+|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
+
+#### Testing
+
+Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
+
+* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
+* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
+
+```go
+logger, hook := NewNullLogger()
+logger.Error("Hello error")
+
+assert.Equal(1, len(hook.Entries))
+assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+assert.Equal("Hello error", hook.LastEntry().Message)
+
+hook.Reset()
+assert.Nil(hook.LastEntry())
+```
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/doc.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/doc.go
new file mode 100644
index 00000000..dddd5f87
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/doc.go
@@ -0,0 +1,26 @@
+/*
+Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
+
+
+The simplest way to use Logrus is simply the package-level exported logger:
+
+ package main
+
+ import (
+ log "github.com/Sirupsen/logrus"
+ )
+
+ func main() {
+ log.WithFields(log.Fields{
+ "animal": "walrus",
+ "number": 1,
+ "size": 10,
+ }).Info("A walrus appears")
+ }
+
+Output:
+ time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
+
+For a full guide visit https://github.com/Sirupsen/logrus
+*/
+package logrus
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/entry.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/entry.go
new file mode 100644
index 00000000..9ae900bc
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/entry.go
@@ -0,0 +1,264 @@
+package logrus
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "time"
+)
+
+// Defines the key when adding errors using WithError.
+var ErrorKey = "error"
+
+// An entry is the final or intermediate Logrus logging entry. It contains all
+// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
+// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
+// passed around as much as you wish to avoid field duplication.
+type Entry struct {
+ Logger *Logger
+
+ // Contains all the fields set by the user.
+ Data Fields
+
+ // Time at which the log entry was created
+ Time time.Time
+
+ // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
+ Level Level
+
+ // Message passed to Debug, Info, Warn, Error, Fatal or Panic
+ Message string
+}
+
+func NewEntry(logger *Logger) *Entry {
+ return &Entry{
+ Logger: logger,
+ // Default is three fields, give a little extra room
+ Data: make(Fields, 5),
+ }
+}
+
+// Returns a reader for the entry, which is a proxy to the formatter.
+func (entry *Entry) Reader() (*bytes.Buffer, error) {
+ serialized, err := entry.Logger.Formatter.Format(entry)
+ return bytes.NewBuffer(serialized), err
+}
+
+// Returns the string representation from the reader and ultimately the
+// formatter.
+func (entry *Entry) String() (string, error) {
+ reader, err := entry.Reader()
+ if err != nil {
+ return "", err
+ }
+
+ return reader.String(), err
+}
+
+// Add an error as single field (using the key defined in ErrorKey) to the Entry.
+func (entry *Entry) WithError(err error) *Entry {
+ return entry.WithField(ErrorKey, err)
+}
+
+// Add a single field to the Entry.
+func (entry *Entry) WithField(key string, value interface{}) *Entry {
+ return entry.WithFields(Fields{key: value})
+}
+
+// Add a map of fields to the Entry.
+func (entry *Entry) WithFields(fields Fields) *Entry {
+ data := Fields{}
+ for k, v := range entry.Data {
+ data[k] = v
+ }
+ for k, v := range fields {
+ data[k] = v
+ }
+ return &Entry{Logger: entry.Logger, Data: data}
+}
+
+// This function is not declared with a pointer value because otherwise
+// race conditions will occur when using multiple goroutines
+func (entry Entry) log(level Level, msg string) {
+ entry.Time = time.Now()
+ entry.Level = level
+ entry.Message = msg
+
+ if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
+ entry.Logger.mu.Lock()
+ fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
+ entry.Logger.mu.Unlock()
+ }
+
+ reader, err := entry.Reader()
+ if err != nil {
+ entry.Logger.mu.Lock()
+ fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
+ entry.Logger.mu.Unlock()
+ }
+
+ entry.Logger.mu.Lock()
+ defer entry.Logger.mu.Unlock()
+
+ _, err = io.Copy(entry.Logger.Out, reader)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
+ }
+
+ // To avoid Entry#log() returning a value that only would make sense for
+ // panic() to use in Entry#Panic(), we avoid the allocation by checking
+ // directly here.
+ if level <= PanicLevel {
+ panic(&entry)
+ }
+}
+
+func (entry *Entry) Debug(args ...interface{}) {
+ if entry.Logger.Level >= DebugLevel {
+ entry.log(DebugLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Print(args ...interface{}) {
+ entry.Info(args...)
+}
+
+func (entry *Entry) Info(args ...interface{}) {
+ if entry.Logger.Level >= InfoLevel {
+ entry.log(InfoLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Warn(args ...interface{}) {
+ if entry.Logger.Level >= WarnLevel {
+ entry.log(WarnLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Warning(args ...interface{}) {
+ entry.Warn(args...)
+}
+
+func (entry *Entry) Error(args ...interface{}) {
+ if entry.Logger.Level >= ErrorLevel {
+ entry.log(ErrorLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Fatal(args ...interface{}) {
+ if entry.Logger.Level >= FatalLevel {
+ entry.log(FatalLevel, fmt.Sprint(args...))
+ }
+ os.Exit(1)
+}
+
+func (entry *Entry) Panic(args ...interface{}) {
+ if entry.Logger.Level >= PanicLevel {
+ entry.log(PanicLevel, fmt.Sprint(args...))
+ }
+ panic(fmt.Sprint(args...))
+}
+
+// Entry Printf family functions
+
+func (entry *Entry) Debugf(format string, args ...interface{}) {
+ if entry.Logger.Level >= DebugLevel {
+ entry.Debug(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Infof(format string, args ...interface{}) {
+ if entry.Logger.Level >= InfoLevel {
+ entry.Info(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Printf(format string, args ...interface{}) {
+ entry.Infof(format, args...)
+}
+
+func (entry *Entry) Warnf(format string, args ...interface{}) {
+ if entry.Logger.Level >= WarnLevel {
+ entry.Warn(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Warningf(format string, args ...interface{}) {
+ entry.Warnf(format, args...)
+}
+
+func (entry *Entry) Errorf(format string, args ...interface{}) {
+ if entry.Logger.Level >= ErrorLevel {
+ entry.Error(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Fatalf(format string, args ...interface{}) {
+ if entry.Logger.Level >= FatalLevel {
+ entry.Fatal(fmt.Sprintf(format, args...))
+ }
+ os.Exit(1)
+}
+
+func (entry *Entry) Panicf(format string, args ...interface{}) {
+ if entry.Logger.Level >= PanicLevel {
+ entry.Panic(fmt.Sprintf(format, args...))
+ }
+}
+
+// Entry Println family functions
+
+func (entry *Entry) Debugln(args ...interface{}) {
+ if entry.Logger.Level >= DebugLevel {
+ entry.Debug(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Infoln(args ...interface{}) {
+ if entry.Logger.Level >= InfoLevel {
+ entry.Info(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Println(args ...interface{}) {
+ entry.Infoln(args...)
+}
+
+func (entry *Entry) Warnln(args ...interface{}) {
+ if entry.Logger.Level >= WarnLevel {
+ entry.Warn(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Warningln(args ...interface{}) {
+ entry.Warnln(args...)
+}
+
+func (entry *Entry) Errorln(args ...interface{}) {
+ if entry.Logger.Level >= ErrorLevel {
+ entry.Error(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Fatalln(args ...interface{}) {
+ if entry.Logger.Level >= FatalLevel {
+ entry.Fatal(entry.sprintlnn(args...))
+ }
+ os.Exit(1)
+}
+
+func (entry *Entry) Panicln(args ...interface{}) {
+ if entry.Logger.Level >= PanicLevel {
+ entry.Panic(entry.sprintlnn(args...))
+ }
+}
+
+// Sprintlnn => Sprint no newline. This is to get the behavior of how
+// fmt.Sprintln where spaces are always added between operands, regardless of
+// their type. Instead of vendoring the Sprintln implementation to spare a
+// string allocation, we do the simplest thing.
+func (entry *Entry) sprintlnn(args ...interface{}) string {
+ msg := fmt.Sprintln(args...)
+ return msg[:len(msg)-1]
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/entry_test.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/entry_test.go
new file mode 100644
index 00000000..99c3b41d
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/entry_test.go
@@ -0,0 +1,77 @@
+package logrus
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestEntryWithError(t *testing.T) {
+
+ assert := assert.New(t)
+
+ defer func() {
+ ErrorKey = "error"
+ }()
+
+ err := fmt.Errorf("kaboom at layer %d", 4711)
+
+ assert.Equal(err, WithError(err).Data["error"])
+
+ logger := New()
+ logger.Out = &bytes.Buffer{}
+ entry := NewEntry(logger)
+
+ assert.Equal(err, entry.WithError(err).Data["error"])
+
+ ErrorKey = "err"
+
+ assert.Equal(err, entry.WithError(err).Data["err"])
+
+}
+
+func TestEntryPanicln(t *testing.T) {
+ errBoom := fmt.Errorf("boom time")
+
+ defer func() {
+ p := recover()
+ assert.NotNil(t, p)
+
+ switch pVal := p.(type) {
+ case *Entry:
+ assert.Equal(t, "kaboom", pVal.Message)
+ assert.Equal(t, errBoom, pVal.Data["err"])
+ default:
+ t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
+ }
+ }()
+
+ logger := New()
+ logger.Out = &bytes.Buffer{}
+ entry := NewEntry(logger)
+ entry.WithField("err", errBoom).Panicln("kaboom")
+}
+
+func TestEntryPanicf(t *testing.T) {
+ errBoom := fmt.Errorf("boom again")
+
+ defer func() {
+ p := recover()
+ assert.NotNil(t, p)
+
+ switch pVal := p.(type) {
+ case *Entry:
+ assert.Equal(t, "kaboom true", pVal.Message)
+ assert.Equal(t, errBoom, pVal.Data["err"])
+ default:
+ t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
+ }
+ }()
+
+ logger := New()
+ logger.Out = &bytes.Buffer{}
+ entry := NewEntry(logger)
+ entry.WithField("err", errBoom).Panicf("kaboom %v", true)
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
new file mode 100644
index 00000000..a1623ec0
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+ "github.com/Sirupsen/logrus"
+)
+
+var log = logrus.New()
+
+func init() {
+ log.Formatter = new(logrus.JSONFormatter)
+ log.Formatter = new(logrus.TextFormatter) // default
+ log.Level = logrus.DebugLevel
+}
+
+func main() {
+ defer func() {
+ err := recover()
+ if err != nil {
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "err": err,
+ "number": 100,
+ }).Fatal("The ice breaks!")
+ }
+ }()
+
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "number": 8,
+ }).Debug("Started observing beach")
+
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "number": 122,
+ }).Warn("The group's number increased tremendously!")
+
+ log.WithFields(logrus.Fields{
+ "temperature": -4,
+ }).Debug("Temperature changes")
+
+ log.WithFields(logrus.Fields{
+ "animal": "orca",
+ "size": 9009,
+ }).Panic("It's over 9000!")
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
new file mode 100644
index 00000000..3187f6d3
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
@@ -0,0 +1,30 @@
+package main
+
+import (
+ "github.com/Sirupsen/logrus"
+ "gopkg.in/gemnasium/logrus-airbrake-hook.v2"
+)
+
+var log = logrus.New()
+
+func init() {
+ log.Formatter = new(logrus.TextFormatter) // default
+ log.Hooks.Add(airbrake.NewHook(123, "xyz", "development"))
+}
+
+func main() {
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "number": 122,
+ }).Warn("The group's number increased tremendously!")
+
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "number": 100,
+ }).Fatal("The ice breaks!")
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/exported.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/exported.go
new file mode 100644
index 00000000..9a0120ac
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/exported.go
@@ -0,0 +1,193 @@
+package logrus
+
+import (
+ "io"
+)
+
+var (
+ // std is the name of the standard logger in stdlib `log`
+ std = New()
+)
+
+func StandardLogger() *Logger {
+ return std
+}
+
+// SetOutput sets the standard logger output.
+func SetOutput(out io.Writer) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Out = out
+}
+
+// SetFormatter sets the standard logger formatter.
+func SetFormatter(formatter Formatter) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Formatter = formatter
+}
+
+// SetLevel sets the standard logger level.
+func SetLevel(level Level) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Level = level
+}
+
+// GetLevel returns the standard logger level.
+func GetLevel() Level {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ return std.Level
+}
+
+// AddHook adds a hook to the standard logger hooks.
+func AddHook(hook Hook) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Hooks.Add(hook)
+}
+
+// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
+func WithError(err error) *Entry {
+ return std.WithField(ErrorKey, err)
+}
+
+// WithField creates an entry from the standard logger and adds a field to
+// it. If you want multiple fields, use `WithFields`.
+//
+// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
+// or Panic on the Entry it returns.
+func WithField(key string, value interface{}) *Entry {
+ return std.WithField(key, value)
+}
+
+// WithFields creates an entry from the standard logger and adds multiple
+// fields to it. This is simply a helper for `WithField`, invoking it
+// once for each field.
+//
+// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
+// or Panic on the Entry it returns.
+func WithFields(fields Fields) *Entry {
+ return std.WithFields(fields)
+}
+
+// Debug logs a message at level Debug on the standard logger.
+func Debug(args ...interface{}) {
+ std.Debug(args...)
+}
+
+// Print logs a message at level Info on the standard logger.
+func Print(args ...interface{}) {
+ std.Print(args...)
+}
+
+// Info logs a message at level Info on the standard logger.
+func Info(args ...interface{}) {
+ std.Info(args...)
+}
+
+// Warn logs a message at level Warn on the standard logger.
+func Warn(args ...interface{}) {
+ std.Warn(args...)
+}
+
+// Warning logs a message at level Warn on the standard logger.
+func Warning(args ...interface{}) {
+ std.Warning(args...)
+}
+
+// Error logs a message at level Error on the standard logger.
+func Error(args ...interface{}) {
+ std.Error(args...)
+}
+
+// Panic logs a message at level Panic on the standard logger.
+func Panic(args ...interface{}) {
+ std.Panic(args...)
+}
+
+// Fatal logs a message at level Fatal on the standard logger.
+func Fatal(args ...interface{}) {
+ std.Fatal(args...)
+}
+
+// Debugf logs a message at level Debug on the standard logger.
+func Debugf(format string, args ...interface{}) {
+ std.Debugf(format, args...)
+}
+
+// Printf logs a message at level Info on the standard logger.
+func Printf(format string, args ...interface{}) {
+ std.Printf(format, args...)
+}
+
+// Infof logs a message at level Info on the standard logger.
+func Infof(format string, args ...interface{}) {
+ std.Infof(format, args...)
+}
+
+// Warnf logs a message at level Warn on the standard logger.
+func Warnf(format string, args ...interface{}) {
+ std.Warnf(format, args...)
+}
+
+// Warningf logs a message at level Warn on the standard logger.
+func Warningf(format string, args ...interface{}) {
+ std.Warningf(format, args...)
+}
+
+// Errorf logs a message at level Error on the standard logger.
+func Errorf(format string, args ...interface{}) {
+ std.Errorf(format, args...)
+}
+
+// Panicf logs a message at level Panic on the standard logger.
+func Panicf(format string, args ...interface{}) {
+ std.Panicf(format, args...)
+}
+
+// Fatalf logs a message at level Fatal on the standard logger.
+func Fatalf(format string, args ...interface{}) {
+ std.Fatalf(format, args...)
+}
+
+// Debugln logs a message at level Debug on the standard logger.
+func Debugln(args ...interface{}) {
+ std.Debugln(args...)
+}
+
+// Println logs a message at level Info on the standard logger.
+func Println(args ...interface{}) {
+ std.Println(args...)
+}
+
+// Infoln logs a message at level Info on the standard logger.
+func Infoln(args ...interface{}) {
+ std.Infoln(args...)
+}
+
+// Warnln logs a message at level Warn on the standard logger.
+func Warnln(args ...interface{}) {
+ std.Warnln(args...)
+}
+
+// Warningln logs a message at level Warn on the standard logger.
+func Warningln(args ...interface{}) {
+ std.Warningln(args...)
+}
+
+// Errorln logs a message at level Error on the standard logger.
+func Errorln(args ...interface{}) {
+ std.Errorln(args...)
+}
+
+// Panicln logs a message at level Panic on the standard logger.
+func Panicln(args ...interface{}) {
+ std.Panicln(args...)
+}
+
+// Fatalln logs a message at level Fatal on the standard logger.
+func Fatalln(args ...interface{}) {
+ std.Fatalln(args...)
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatter.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatter.go
new file mode 100644
index 00000000..104d689f
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatter.go
@@ -0,0 +1,48 @@
+package logrus
+
+import "time"
+
+const DefaultTimestampFormat = time.RFC3339
+
+// The Formatter interface is used to implement a custom Formatter. It takes an
+// `Entry`. It exposes all the fields, including the default ones:
+//
+// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
+// * `entry.Data["time"]`. The timestamp.
+// * `entry.Data["level"]. The level the entry was logged at.
+//
+// Any additional fields added with `WithField` or `WithFields` are also in
+// `entry.Data`. Format is expected to return an array of bytes which are then
+// logged to `logger.Out`.
+type Formatter interface {
+ Format(*Entry) ([]byte, error)
+}
+
+// This is to not silently overwrite `time`, `msg` and `level` fields when
+// dumping it. If this code wasn't there doing:
+//
+// logrus.WithField("level", 1).Info("hello")
+//
+// Would just silently drop the user provided level. Instead with this code
+// it'll logged as:
+//
+// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
+//
+// It's not exported because it's still using Data in an opinionated way. It's to
+// avoid code duplication between the two default formatters.
+func prefixFieldClashes(data Fields) {
+ _, ok := data["time"]
+ if ok {
+ data["fields.time"] = data["time"]
+ }
+
+ _, ok = data["msg"]
+ if ok {
+ data["fields.msg"] = data["msg"]
+ }
+
+ _, ok = data["level"]
+ if ok {
+ data["fields.level"] = data["level"]
+ }
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
new file mode 100644
index 00000000..c6d290c7
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
@@ -0,0 +1,98 @@
+package logrus
+
+import (
+ "fmt"
+ "testing"
+ "time"
+)
+
+// smallFields is a small size data set for benchmarking
+var smallFields = Fields{
+ "foo": "bar",
+ "baz": "qux",
+ "one": "two",
+ "three": "four",
+}
+
+// largeFields is a large size data set for benchmarking
+var largeFields = Fields{
+ "foo": "bar",
+ "baz": "qux",
+ "one": "two",
+ "three": "four",
+ "five": "six",
+ "seven": "eight",
+ "nine": "ten",
+ "eleven": "twelve",
+ "thirteen": "fourteen",
+ "fifteen": "sixteen",
+ "seventeen": "eighteen",
+ "nineteen": "twenty",
+ "a": "b",
+ "c": "d",
+ "e": "f",
+ "g": "h",
+ "i": "j",
+ "k": "l",
+ "m": "n",
+ "o": "p",
+ "q": "r",
+ "s": "t",
+ "u": "v",
+ "w": "x",
+ "y": "z",
+ "this": "will",
+ "make": "thirty",
+ "entries": "yeah",
+}
+
+var errorFields = Fields{
+ "foo": fmt.Errorf("bar"),
+ "baz": fmt.Errorf("qux"),
+}
+
+func BenchmarkErrorTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{DisableColors: true}, errorFields)
+}
+
+func BenchmarkSmallTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields)
+}
+
+func BenchmarkLargeTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields)
+}
+
+func BenchmarkSmallColoredTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields)
+}
+
+func BenchmarkLargeColoredTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields)
+}
+
+func BenchmarkSmallJSONFormatter(b *testing.B) {
+ doBenchmark(b, &JSONFormatter{}, smallFields)
+}
+
+func BenchmarkLargeJSONFormatter(b *testing.B) {
+ doBenchmark(b, &JSONFormatter{}, largeFields)
+}
+
+func doBenchmark(b *testing.B, formatter Formatter, fields Fields) {
+ entry := &Entry{
+ Time: time.Time{},
+ Level: InfoLevel,
+ Message: "message",
+ Data: fields,
+ }
+ var d []byte
+ var err error
+ for i := 0; i < b.N; i++ {
+ d, err = formatter.Format(entry)
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.SetBytes(int64(len(d)))
+ }
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
new file mode 100644
index 00000000..aad646ab
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
@@ -0,0 +1,61 @@
+package logstash
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "github.com/Sirupsen/logrus"
+)
+
+// Formatter generates json in logstash format.
+// Logstash site: http://logstash.net/
+type LogstashFormatter struct {
+ Type string // if not empty use for logstash type field.
+
+ // TimestampFormat sets the format used for timestamps.
+ TimestampFormat string
+}
+
+func (f *LogstashFormatter) Format(entry *logrus.Entry) ([]byte, error) {
+ fields := make(logrus.Fields)
+ for k, v := range entry.Data {
+ fields[k] = v
+ }
+
+ fields["@version"] = 1
+
+ if f.TimestampFormat == "" {
+ f.TimestampFormat = logrus.DefaultTimestampFormat
+ }
+
+ fields["@timestamp"] = entry.Time.Format(f.TimestampFormat)
+
+ // set message field
+ v, ok := entry.Data["message"]
+ if ok {
+ fields["fields.message"] = v
+ }
+ fields["message"] = entry.Message
+
+ // set level field
+ v, ok = entry.Data["level"]
+ if ok {
+ fields["fields.level"] = v
+ }
+ fields["level"] = entry.Level.String()
+
+ // set type field
+ if f.Type != "" {
+ v, ok = entry.Data["type"]
+ if ok {
+ fields["fields.type"] = v
+ }
+ fields["type"] = f.Type
+ }
+
+ serialized, err := json.Marshal(fields)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+ }
+ return append(serialized, '\n'), nil
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go
new file mode 100644
index 00000000..d8814a0e
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go
@@ -0,0 +1,52 @@
+package logstash
+
+import (
+ "bytes"
+ "encoding/json"
+ "github.com/Sirupsen/logrus"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestLogstashFormatter(t *testing.T) {
+ assert := assert.New(t)
+
+ lf := LogstashFormatter{Type: "abc"}
+
+ fields := logrus.Fields{
+ "message": "def",
+ "level": "ijk",
+ "type": "lmn",
+ "one": 1,
+ "pi": 3.14,
+ "bool": true,
+ }
+
+ entry := logrus.WithFields(fields)
+ entry.Message = "msg"
+ entry.Level = logrus.InfoLevel
+
+ b, _ := lf.Format(entry)
+
+ var data map[string]interface{}
+ dec := json.NewDecoder(bytes.NewReader(b))
+ dec.UseNumber()
+ dec.Decode(&data)
+
+ // base fields
+ assert.Equal(json.Number("1"), data["@version"])
+ assert.NotEmpty(data["@timestamp"])
+ assert.Equal("abc", data["type"])
+ assert.Equal("msg", data["message"])
+ assert.Equal("info", data["level"])
+
+ // substituted fields
+ assert.Equal("def", data["fields.message"])
+ assert.Equal("ijk", data["fields.level"])
+ assert.Equal("lmn", data["fields.type"])
+
+ // formats
+ assert.Equal(json.Number("1"), data["one"])
+ assert.Equal(json.Number("3.14"), data["pi"])
+ assert.Equal(true, data["bool"])
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hook_test.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hook_test.go
new file mode 100644
index 00000000..13f34cb6
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hook_test.go
@@ -0,0 +1,122 @@
+package logrus
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+type TestHook struct {
+ Fired bool
+}
+
+func (hook *TestHook) Fire(entry *Entry) error {
+ hook.Fired = true
+ return nil
+}
+
+func (hook *TestHook) Levels() []Level {
+ return []Level{
+ DebugLevel,
+ InfoLevel,
+ WarnLevel,
+ ErrorLevel,
+ FatalLevel,
+ PanicLevel,
+ }
+}
+
+func TestHookFires(t *testing.T) {
+ hook := new(TestHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ assert.Equal(t, hook.Fired, false)
+
+ log.Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, hook.Fired, true)
+ })
+}
+
+type ModifyHook struct {
+}
+
+func (hook *ModifyHook) Fire(entry *Entry) error {
+ entry.Data["wow"] = "whale"
+ return nil
+}
+
+func (hook *ModifyHook) Levels() []Level {
+ return []Level{
+ DebugLevel,
+ InfoLevel,
+ WarnLevel,
+ ErrorLevel,
+ FatalLevel,
+ PanicLevel,
+ }
+}
+
+func TestHookCanModifyEntry(t *testing.T) {
+ hook := new(ModifyHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ log.WithField("wow", "elephant").Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["wow"], "whale")
+ })
+}
+
+func TestCanFireMultipleHooks(t *testing.T) {
+ hook1 := new(ModifyHook)
+ hook2 := new(TestHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook1)
+ log.Hooks.Add(hook2)
+
+ log.WithField("wow", "elephant").Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["wow"], "whale")
+ assert.Equal(t, hook2.Fired, true)
+ })
+}
+
+type ErrorHook struct {
+ Fired bool
+}
+
+func (hook *ErrorHook) Fire(entry *Entry) error {
+ hook.Fired = true
+ return nil
+}
+
+func (hook *ErrorHook) Levels() []Level {
+ return []Level{
+ ErrorLevel,
+ }
+}
+
+func TestErrorHookShouldntFireOnInfo(t *testing.T) {
+ hook := new(ErrorHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ log.Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, hook.Fired, false)
+ })
+}
+
+func TestErrorHookShouldFireOnError(t *testing.T) {
+ hook := new(ErrorHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ log.Error("test")
+ }, func(fields Fields) {
+ assert.Equal(t, hook.Fired, true)
+ })
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks.go
new file mode 100644
index 00000000..3f151cdc
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks.go
@@ -0,0 +1,34 @@
+package logrus
+
+// A hook to be fired when logging on the logging levels returned from
+// `Levels()` on your implementation of the interface. Note that this is not
+// fired in a goroutine or a channel with workers, you should handle such
+// functionality yourself if your call is non-blocking and you don't wish for
+// the logging calls for levels returned from `Levels()` to block.
+type Hook interface {
+ Levels() []Level
+ Fire(*Entry) error
+}
+
+// Internal type for storing the hooks on a logger instance.
+type LevelHooks map[Level][]Hook
+
+// Add a hook to an instance of logger. This is called with
+// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
+func (hooks LevelHooks) Add(hook Hook) {
+ for _, level := range hook.Levels() {
+ hooks[level] = append(hooks[level], hook)
+ }
+}
+
+// Fire all the hooks for the passed level. Used by `entry.log` to fire
+// appropriate hooks for a log entry.
+func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
+ for _, hook := range hooks[level] {
+ if err := hook.Fire(entry); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
new file mode 100644
index 00000000..066704b3
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
@@ -0,0 +1,39 @@
+# Syslog Hooks for Logrus
+
+## Usage
+
+```go
+import (
+ "log/syslog"
+ "github.com/Sirupsen/logrus"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+```
+
+If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). Just assign empty string to the first two parameters of `NewSyslogHook`. It should look like the following.
+
+```go
+import (
+ "log/syslog"
+ "github.com/Sirupsen/logrus"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+```
\ No newline at end of file
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
new file mode 100644
index 00000000..a36e2003
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
@@ -0,0 +1,54 @@
+// +build !windows,!nacl,!plan9
+
+package logrus_syslog
+
+import (
+ "fmt"
+ "github.com/Sirupsen/logrus"
+ "log/syslog"
+ "os"
+)
+
+// SyslogHook to send logs via syslog.
+type SyslogHook struct {
+ Writer *syslog.Writer
+ SyslogNetwork string
+ SyslogRaddr string
+}
+
+// Creates a hook to be added to an instance of logger. This is called with
+// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
+// `if err == nil { log.Hooks.Add(hook) }`
+func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
+ w, err := syslog.Dial(network, raddr, priority, tag)
+ return &SyslogHook{w, network, raddr}, err
+}
+
+func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
+ line, err := entry.String()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
+ return err
+ }
+
+ switch entry.Level {
+ case logrus.PanicLevel:
+ return hook.Writer.Crit(line)
+ case logrus.FatalLevel:
+ return hook.Writer.Crit(line)
+ case logrus.ErrorLevel:
+ return hook.Writer.Err(line)
+ case logrus.WarnLevel:
+ return hook.Writer.Warning(line)
+ case logrus.InfoLevel:
+ return hook.Writer.Info(line)
+ case logrus.DebugLevel:
+ return hook.Writer.Debug(line)
+ default:
+ return nil
+ }
+}
+
+func (hook *SyslogHook) Levels() []logrus.Level {
+ return logrus.AllLevels
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
new file mode 100644
index 00000000..42762dc1
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
@@ -0,0 +1,26 @@
+package logrus_syslog
+
+import (
+ "github.com/Sirupsen/logrus"
+ "log/syslog"
+ "testing"
+)
+
+func TestLocalhostAddAndPrint(t *testing.T) {
+ log := logrus.New()
+ hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+
+ if err != nil {
+ t.Errorf("Unable to connect to local syslog.")
+ }
+
+ log.Hooks.Add(hook)
+
+ for _, level := range hook.Levels() {
+ if len(log.Hooks[level]) != 1 {
+ t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
+ }
+ }
+
+ log.Info("Congratulations!")
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/test/test.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/test/test.go
new file mode 100644
index 00000000..06881253
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/test/test.go
@@ -0,0 +1,67 @@
+package test
+
+import (
+ "io/ioutil"
+
+ "github.com/Sirupsen/logrus"
+)
+
+// test.Hook is a hook designed for dealing with logs in test scenarios.
+type Hook struct {
+ Entries []*logrus.Entry
+}
+
+// Installs a test hook for the global logger.
+func NewGlobal() *Hook {
+
+ hook := new(Hook)
+ logrus.AddHook(hook)
+
+ return hook
+
+}
+
+// Installs a test hook for a given local logger.
+func NewLocal(logger *logrus.Logger) *Hook {
+
+ hook := new(Hook)
+ logger.Hooks.Add(hook)
+
+ return hook
+
+}
+
+// Creates a discarding logger and installs the test hook.
+func NewNullLogger() (*logrus.Logger, *Hook) {
+
+ logger := logrus.New()
+ logger.Out = ioutil.Discard
+
+ return logger, NewLocal(logger)
+
+}
+
+func (t *Hook) Fire(e *logrus.Entry) error {
+ t.Entries = append(t.Entries, e)
+ return nil
+}
+
+func (t *Hook) Levels() []logrus.Level {
+ return logrus.AllLevels
+}
+
+// LastEntry returns the last entry that was logged or nil.
+func (t *Hook) LastEntry() (l *logrus.Entry) {
+
+ if i := len(t.Entries) - 1; i < 0 {
+ return nil
+ } else {
+ return t.Entries[i]
+ }
+
+}
+
+// Reset removes all Entries from this test hook.
+func (t *Hook) Reset() {
+ t.Entries = make([]*logrus.Entry, 0)
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
new file mode 100644
index 00000000..d69455ba
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
@@ -0,0 +1,39 @@
+package test
+
+import (
+ "testing"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAllHooks(t *testing.T) {
+
+ assert := assert.New(t)
+
+ logger, hook := NewNullLogger()
+ assert.Nil(hook.LastEntry())
+ assert.Equal(0, len(hook.Entries))
+
+ logger.Error("Hello error")
+ assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+ assert.Equal("Hello error", hook.LastEntry().Message)
+ assert.Equal(1, len(hook.Entries))
+
+ logger.Warn("Hello warning")
+ assert.Equal(logrus.WarnLevel, hook.LastEntry().Level)
+ assert.Equal("Hello warning", hook.LastEntry().Message)
+ assert.Equal(2, len(hook.Entries))
+
+ hook.Reset()
+ assert.Nil(hook.LastEntry())
+ assert.Equal(0, len(hook.Entries))
+
+ hook = NewGlobal()
+
+ logrus.Error("Hello error")
+ assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+ assert.Equal("Hello error", hook.LastEntry().Message)
+ assert.Equal(1, len(hook.Entries))
+
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/json_formatter.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/json_formatter.go
new file mode 100644
index 00000000..2ad6dc5c
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/json_formatter.go
@@ -0,0 +1,41 @@
+package logrus
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+type JSONFormatter struct {
+ // TimestampFormat sets the format used for marshaling timestamps.
+ TimestampFormat string
+}
+
+func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
+ data := make(Fields, len(entry.Data)+3)
+ for k, v := range entry.Data {
+ switch v := v.(type) {
+ case error:
+ // Otherwise errors are ignored by `encoding/json`
+ // https://github.com/Sirupsen/logrus/issues/137
+ data[k] = v.Error()
+ default:
+ data[k] = v
+ }
+ }
+ prefixFieldClashes(data)
+
+ timestampFormat := f.TimestampFormat
+ if timestampFormat == "" {
+ timestampFormat = DefaultTimestampFormat
+ }
+
+ data["time"] = entry.Time.Format(timestampFormat)
+ data["msg"] = entry.Message
+ data["level"] = entry.Level.String()
+
+ serialized, err := json.Marshal(data)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+ }
+ return append(serialized, '\n'), nil
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/json_formatter_test.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/json_formatter_test.go
new file mode 100644
index 00000000..1d708732
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/json_formatter_test.go
@@ -0,0 +1,120 @@
+package logrus
+
+import (
+ "encoding/json"
+ "errors"
+
+ "testing"
+)
+
+func TestErrorNotLost(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("error", errors.New("wild walrus")))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["error"] != "wild walrus" {
+ t.Fatal("Error field not set")
+ }
+}
+
+func TestErrorNotLostOnFieldNotNamedError(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("omg", errors.New("wild walrus")))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["omg"] != "wild walrus" {
+ t.Fatal("Error field not set")
+ }
+}
+
+func TestFieldClashWithTime(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("time", "right now!"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["fields.time"] != "right now!" {
+ t.Fatal("fields.time not set to original time field")
+ }
+
+ if entry["time"] != "0001-01-01T00:00:00Z" {
+ t.Fatal("time field not set to current time, was: ", entry["time"])
+ }
+}
+
+func TestFieldClashWithMsg(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("msg", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["fields.msg"] != "something" {
+ t.Fatal("fields.msg not set to original msg field")
+ }
+}
+
+func TestFieldClashWithLevel(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("level", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["fields.level"] != "something" {
+ t.Fatal("fields.level not set to original level field")
+ }
+}
+
+func TestJSONEntryEndsWithNewline(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("level", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ if b[len(b)-1] != '\n' {
+ t.Fatal("Expected JSON log entry to end with a newline")
+ }
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/logger.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/logger.go
new file mode 100644
index 00000000..2fdb2317
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/logger.go
@@ -0,0 +1,212 @@
+package logrus
+
+import (
+ "io"
+ "os"
+ "sync"
+)
+
+type Logger struct {
+ // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
+ // file, or leave it default which is `os.Stderr`. You can also set this to
+ // something more adventorous, such as logging to Kafka.
+ Out io.Writer
+ // Hooks for the logger instance. These allow firing events based on logging
+ // levels and log entries. For example, to send errors to an error tracking
+ // service, log to StatsD or dump the core on fatal errors.
+ Hooks LevelHooks
+ // All log entries pass through the formatter before logged to Out. The
+ // included formatters are `TextFormatter` and `JSONFormatter` for which
+ // TextFormatter is the default. In development (when a TTY is attached) it
+ // logs with colors, but to a file it wouldn't. You can easily implement your
+ // own that implements the `Formatter` interface, see the `README` or included
+ // formatters for examples.
+ Formatter Formatter
+ // The logging level the logger should log at. This is typically (and defaults
+ // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
+ // logged. `logrus.Debug` is useful in
+ Level Level
+ // Used to sync writing to the log.
+ mu sync.Mutex
+}
+
+// Creates a new logger. Configuration should be set by changing `Formatter`,
+// `Out` and `Hooks` directly on the default logger instance. You can also just
+// instantiate your own:
+//
+// var log = &Logger{
+// Out: os.Stderr,
+// Formatter: new(JSONFormatter),
+// Hooks: make(LevelHooks),
+// Level: logrus.DebugLevel,
+// }
+//
+// It's recommended to make this a global instance called `log`.
+func New() *Logger {
+ return &Logger{
+ Out: os.Stderr,
+ Formatter: new(TextFormatter),
+ Hooks: make(LevelHooks),
+ Level: InfoLevel,
+ }
+}
+
+// Adds a field to the log entry, note that you it doesn't log until you call
+// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
+// If you want multiple fields, use `WithFields`.
+func (logger *Logger) WithField(key string, value interface{}) *Entry {
+ return NewEntry(logger).WithField(key, value)
+}
+
+// Adds a struct of fields to the log entry. All it does is call `WithField` for
+// each `Field`.
+func (logger *Logger) WithFields(fields Fields) *Entry {
+ return NewEntry(logger).WithFields(fields)
+}
+
+// Add an error as single field to the log entry. All it does is call
+// `WithError` for the given `error`.
+func (logger *Logger) WithError(err error) *Entry {
+ return NewEntry(logger).WithError(err)
+}
+
+func (logger *Logger) Debugf(format string, args ...interface{}) {
+ if logger.Level >= DebugLevel {
+ NewEntry(logger).Debugf(format, args...)
+ }
+}
+
+func (logger *Logger) Infof(format string, args ...interface{}) {
+ if logger.Level >= InfoLevel {
+ NewEntry(logger).Infof(format, args...)
+ }
+}
+
+func (logger *Logger) Printf(format string, args ...interface{}) {
+ NewEntry(logger).Printf(format, args...)
+}
+
+func (logger *Logger) Warnf(format string, args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warnf(format, args...)
+ }
+}
+
+func (logger *Logger) Warningf(format string, args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warnf(format, args...)
+ }
+}
+
+func (logger *Logger) Errorf(format string, args ...interface{}) {
+ if logger.Level >= ErrorLevel {
+ NewEntry(logger).Errorf(format, args...)
+ }
+}
+
+func (logger *Logger) Fatalf(format string, args ...interface{}) {
+ if logger.Level >= FatalLevel {
+ NewEntry(logger).Fatalf(format, args...)
+ }
+ os.Exit(1)
+}
+
+func (logger *Logger) Panicf(format string, args ...interface{}) {
+ if logger.Level >= PanicLevel {
+ NewEntry(logger).Panicf(format, args...)
+ }
+}
+
+func (logger *Logger) Debug(args ...interface{}) {
+ if logger.Level >= DebugLevel {
+ NewEntry(logger).Debug(args...)
+ }
+}
+
+func (logger *Logger) Info(args ...interface{}) {
+ if logger.Level >= InfoLevel {
+ NewEntry(logger).Info(args...)
+ }
+}
+
+func (logger *Logger) Print(args ...interface{}) {
+ NewEntry(logger).Info(args...)
+}
+
+func (logger *Logger) Warn(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warn(args...)
+ }
+}
+
+func (logger *Logger) Warning(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warn(args...)
+ }
+}
+
+func (logger *Logger) Error(args ...interface{}) {
+ if logger.Level >= ErrorLevel {
+ NewEntry(logger).Error(args...)
+ }
+}
+
+func (logger *Logger) Fatal(args ...interface{}) {
+ if logger.Level >= FatalLevel {
+ NewEntry(logger).Fatal(args...)
+ }
+ os.Exit(1)
+}
+
+func (logger *Logger) Panic(args ...interface{}) {
+ if logger.Level >= PanicLevel {
+ NewEntry(logger).Panic(args...)
+ }
+}
+
+func (logger *Logger) Debugln(args ...interface{}) {
+ if logger.Level >= DebugLevel {
+ NewEntry(logger).Debugln(args...)
+ }
+}
+
+func (logger *Logger) Infoln(args ...interface{}) {
+ if logger.Level >= InfoLevel {
+ NewEntry(logger).Infoln(args...)
+ }
+}
+
+func (logger *Logger) Println(args ...interface{}) {
+ NewEntry(logger).Println(args...)
+}
+
+func (logger *Logger) Warnln(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warnln(args...)
+ }
+}
+
+func (logger *Logger) Warningln(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warnln(args...)
+ }
+}
+
+func (logger *Logger) Errorln(args ...interface{}) {
+ if logger.Level >= ErrorLevel {
+ NewEntry(logger).Errorln(args...)
+ }
+}
+
+func (logger *Logger) Fatalln(args ...interface{}) {
+ if logger.Level >= FatalLevel {
+ NewEntry(logger).Fatalln(args...)
+ }
+ os.Exit(1)
+}
+
+func (logger *Logger) Panicln(args ...interface{}) {
+ if logger.Level >= PanicLevel {
+ NewEntry(logger).Panicln(args...)
+ }
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/logrus.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/logrus.go
new file mode 100644
index 00000000..1e9670d8
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/logrus.go
@@ -0,0 +1,109 @@
+package logrus
+
+import (
+ "fmt"
+ "log"
+ "strings"
+)
+
+// Fields type, used to pass to `WithFields`.
+type Fields map[string]interface{}
+
+// Level type
+type Level uint8
+
+// Convert the Level to a string. E.g. PanicLevel becomes "panic".
+func (level Level) String() string {
+ switch level {
+ case DebugLevel:
+ return "debug"
+ case InfoLevel:
+ return "info"
+ case WarnLevel:
+ return "warning"
+ case ErrorLevel:
+ return "error"
+ case FatalLevel:
+ return "fatal"
+ case PanicLevel:
+ return "panic"
+ }
+
+ return "unknown"
+}
+
+// ParseLevel takes a string level and returns the Logrus log level constant.
+func ParseLevel(lvl string) (Level, error) {
+ switch strings.ToLower(lvl) {
+ case "panic":
+ return PanicLevel, nil
+ case "fatal":
+ return FatalLevel, nil
+ case "error":
+ return ErrorLevel, nil
+ case "warn", "warning":
+ return WarnLevel, nil
+ case "info":
+ return InfoLevel, nil
+ case "debug":
+ return DebugLevel, nil
+ }
+
+ var l Level
+ return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
+}
+
+// A constant exposing all logging levels
+var AllLevels = []Level{
+ PanicLevel,
+ FatalLevel,
+ ErrorLevel,
+ WarnLevel,
+ InfoLevel,
+ DebugLevel,
+}
+
+// These are the different logging levels. You can set the logging level to log
+// on your instance of logger, obtained with `logrus.New()`.
+const (
+ // PanicLevel level, highest level of severity. Logs and then calls panic with the
+ // message passed to Debug, Info, ...
+ PanicLevel Level = iota
+ // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
+ // logging level is set to Panic.
+ FatalLevel
+ // ErrorLevel level. Logs. Used for errors that should definitely be noted.
+ // Commonly used for hooks to send errors to an error tracking service.
+ ErrorLevel
+ // WarnLevel level. Non-critical entries that deserve eyes.
+ WarnLevel
+ // InfoLevel level. General operational entries about what's going on inside the
+ // application.
+ InfoLevel
+ // DebugLevel level. Usually only enabled when debugging. Very verbose logging.
+ DebugLevel
+)
+
+// Won't compile if StdLogger can't be realized by a log.Logger
+var (
+ _ StdLogger = &log.Logger{}
+ _ StdLogger = &Entry{}
+ _ StdLogger = &Logger{}
+)
+
+// StdLogger is what your logrus-enabled library should take, that way
+// it'll accept a stdlib logger and a logrus logger. There's no standard
+// interface, this is the closest we get, unfortunately.
+type StdLogger interface {
+ Print(...interface{})
+ Printf(string, ...interface{})
+ Println(...interface{})
+
+ Fatal(...interface{})
+ Fatalf(string, ...interface{})
+ Fatalln(...interface{})
+
+ Panic(...interface{})
+ Panicf(string, ...interface{})
+ Panicln(...interface{})
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/logrus_test.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/logrus_test.go
new file mode 100644
index 00000000..2cf03f2f
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/logrus_test.go
@@ -0,0 +1,344 @@
+package logrus
+
+import (
+ "bytes"
+ "encoding/json"
+ "strconv"
+ "strings"
+ "sync"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
+ var buffer bytes.Buffer
+ var fields Fields
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = new(JSONFormatter)
+
+ log(logger)
+
+ err := json.Unmarshal(buffer.Bytes(), &fields)
+ assert.Nil(t, err)
+
+ assertions(fields)
+}
+
+func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
+ var buffer bytes.Buffer
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = &TextFormatter{
+ DisableColors: true,
+ }
+
+ log(logger)
+
+ fields := make(map[string]string)
+ for _, kv := range strings.Split(buffer.String(), " ") {
+ if !strings.Contains(kv, "=") {
+ continue
+ }
+ kvArr := strings.Split(kv, "=")
+ key := strings.TrimSpace(kvArr[0])
+ val := kvArr[1]
+ if kvArr[1][0] == '"' {
+ var err error
+ val, err = strconv.Unquote(val)
+ assert.NoError(t, err)
+ }
+ fields[key] = val
+ }
+ assertions(fields)
+}
+
+func TestPrint(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["level"], "info")
+ })
+}
+
+func TestInfo(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["level"], "info")
+ })
+}
+
+func TestWarn(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Warn("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["level"], "warning")
+ })
+}
+
+func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln("test", "test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test test")
+ })
+}
+
+func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln("test", 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test 10")
+ })
+}
+
+func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln(10, 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "10 10")
+ })
+}
+
+func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln(10, 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "10 10")
+ })
+}
+
+func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Info("test", 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test10")
+ })
+}
+
+func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Info("test", "test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "testtest")
+ })
+}
+
+func TestWithFieldsShouldAllowAssignments(t *testing.T) {
+ var buffer bytes.Buffer
+ var fields Fields
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = new(JSONFormatter)
+
+ localLog := logger.WithFields(Fields{
+ "key1": "value1",
+ })
+
+ localLog.WithField("key2", "value2").Info("test")
+ err := json.Unmarshal(buffer.Bytes(), &fields)
+ assert.Nil(t, err)
+
+ assert.Equal(t, "value2", fields["key2"])
+ assert.Equal(t, "value1", fields["key1"])
+
+ buffer = bytes.Buffer{}
+ fields = Fields{}
+ localLog.Info("test")
+ err = json.Unmarshal(buffer.Bytes(), &fields)
+ assert.Nil(t, err)
+
+ _, ok := fields["key2"]
+ assert.Equal(t, false, ok)
+ assert.Equal(t, "value1", fields["key1"])
+}
+
+func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("msg", "hello").Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ })
+}
+
+func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("msg", "hello").Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["fields.msg"], "hello")
+ })
+}
+
+func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("time", "hello").Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["fields.time"], "hello")
+ })
+}
+
+func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("level", 1).Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["level"], "info")
+ assert.Equal(t, fields["fields.level"], 1.0) // JSON has floats only
+ })
+}
+
+func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
+ LogAndAssertText(t, func(log *Logger) {
+ ll := log.WithField("herp", "derp")
+ ll.Info("hello")
+ ll.Info("bye")
+ }, func(fields map[string]string) {
+ for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
+ if _, ok := fields[fieldName]; ok {
+ t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
+ }
+ }
+ })
+}
+
+func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
+
+ var buffer bytes.Buffer
+ var fields Fields
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = new(JSONFormatter)
+
+ llog := logger.WithField("context", "eating raw fish")
+
+ llog.Info("looks delicious")
+
+ err := json.Unmarshal(buffer.Bytes(), &fields)
+ assert.NoError(t, err, "should have decoded first message")
+ assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
+ assert.Equal(t, fields["msg"], "looks delicious")
+ assert.Equal(t, fields["context"], "eating raw fish")
+
+ buffer.Reset()
+
+ llog.Warn("omg it is!")
+
+ err = json.Unmarshal(buffer.Bytes(), &fields)
+ assert.NoError(t, err, "should have decoded second message")
+ assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
+ assert.Equal(t, fields["msg"], "omg it is!")
+ assert.Equal(t, fields["context"], "eating raw fish")
+ assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
+
+}
+
+func TestConvertLevelToString(t *testing.T) {
+ assert.Equal(t, "debug", DebugLevel.String())
+ assert.Equal(t, "info", InfoLevel.String())
+ assert.Equal(t, "warning", WarnLevel.String())
+ assert.Equal(t, "error", ErrorLevel.String())
+ assert.Equal(t, "fatal", FatalLevel.String())
+ assert.Equal(t, "panic", PanicLevel.String())
+}
+
+func TestParseLevel(t *testing.T) {
+ l, err := ParseLevel("panic")
+ assert.Nil(t, err)
+ assert.Equal(t, PanicLevel, l)
+
+ l, err = ParseLevel("PANIC")
+ assert.Nil(t, err)
+ assert.Equal(t, PanicLevel, l)
+
+ l, err = ParseLevel("fatal")
+ assert.Nil(t, err)
+ assert.Equal(t, FatalLevel, l)
+
+ l, err = ParseLevel("FATAL")
+ assert.Nil(t, err)
+ assert.Equal(t, FatalLevel, l)
+
+ l, err = ParseLevel("error")
+ assert.Nil(t, err)
+ assert.Equal(t, ErrorLevel, l)
+
+ l, err = ParseLevel("ERROR")
+ assert.Nil(t, err)
+ assert.Equal(t, ErrorLevel, l)
+
+ l, err = ParseLevel("warn")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("WARN")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("warning")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("WARNING")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("info")
+ assert.Nil(t, err)
+ assert.Equal(t, InfoLevel, l)
+
+ l, err = ParseLevel("INFO")
+ assert.Nil(t, err)
+ assert.Equal(t, InfoLevel, l)
+
+ l, err = ParseLevel("debug")
+ assert.Nil(t, err)
+ assert.Equal(t, DebugLevel, l)
+
+ l, err = ParseLevel("DEBUG")
+ assert.Nil(t, err)
+ assert.Equal(t, DebugLevel, l)
+
+ l, err = ParseLevel("invalid")
+ assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
+}
+
+func TestGetSetLevelRace(t *testing.T) {
+ wg := sync.WaitGroup{}
+ for i := 0; i < 100; i++ {
+ wg.Add(1)
+ go func(i int) {
+ defer wg.Done()
+ if i%2 == 0 {
+ SetLevel(InfoLevel)
+ } else {
+ GetLevel()
+ }
+ }(i)
+
+ }
+ wg.Wait()
+}
+
+func TestLoggingRace(t *testing.T) {
+ logger := New()
+
+ var wg sync.WaitGroup
+ wg.Add(100)
+
+ for i := 0; i < 100; i++ {
+ go func() {
+ logger.Info("info")
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_bsd.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
new file mode 100644
index 00000000..71f8d67a
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
@@ -0,0 +1,9 @@
+// +build darwin freebsd openbsd netbsd dragonfly
+
+package logrus
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TIOCGETA
+
+type Termios syscall.Termios
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_linux.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_linux.go
new file mode 100644
index 00000000..a2c0b40d
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_linux.go
@@ -0,0 +1,12 @@
+// Based on ssh/terminal:
+// Copyright 2013 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.
+
+package logrus
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TCGETS
+
+type Termios syscall.Termios
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
new file mode 100644
index 00000000..b343b3a3
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
@@ -0,0 +1,21 @@
+// Based on ssh/terminal:
+// Copyright 2011 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.
+
+// +build linux darwin freebsd openbsd netbsd dragonfly
+
+package logrus
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+// IsTerminal returns true if stderr's file descriptor is a terminal.
+func IsTerminal() bool {
+ fd := syscall.Stderr
+ var termios Termios
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+ return err == 0
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_solaris.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
new file mode 100644
index 00000000..3e70bf7b
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
@@ -0,0 +1,15 @@
+// +build solaris
+
+package logrus
+
+import (
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal() bool {
+ _, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
+ return err == nil
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_windows.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_windows.go
new file mode 100644
index 00000000..0146845d
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/terminal_windows.go
@@ -0,0 +1,27 @@
+// Based on ssh/terminal:
+// Copyright 2011 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.
+
+// +build windows
+
+package logrus
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var kernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+var (
+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
+)
+
+// IsTerminal returns true if stderr's file descriptor is a terminal.
+func IsTerminal() bool {
+ fd := syscall.Stderr
+ var st uint32
+ r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
+ return r != 0 && e == 0
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/text_formatter.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/text_formatter.go
new file mode 100644
index 00000000..06ef2023
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/text_formatter.go
@@ -0,0 +1,161 @@
+package logrus
+
+import (
+ "bytes"
+ "fmt"
+ "runtime"
+ "sort"
+ "strings"
+ "time"
+)
+
+const (
+ nocolor = 0
+ red = 31
+ green = 32
+ yellow = 33
+ blue = 34
+ gray = 37
+)
+
+var (
+ baseTimestamp time.Time
+ isTerminal bool
+)
+
+func init() {
+ baseTimestamp = time.Now()
+ isTerminal = IsTerminal()
+}
+
+func miniTS() int {
+ return int(time.Since(baseTimestamp) / time.Second)
+}
+
+type TextFormatter struct {
+ // Set to true to bypass checking for a TTY before outputting colors.
+ ForceColors bool
+
+ // Force disabling colors.
+ DisableColors bool
+
+ // Disable timestamp logging. useful when output is redirected to logging
+ // system that already adds timestamps.
+ DisableTimestamp bool
+
+ // Enable logging the full timestamp when a TTY is attached instead of just
+ // the time passed since beginning of execution.
+ FullTimestamp bool
+
+ // TimestampFormat to use for display when a full timestamp is printed
+ TimestampFormat string
+
+ // The fields are sorted by default for a consistent output. For applications
+ // that log extremely frequently and don't use the JSON formatter this may not
+ // be desired.
+ DisableSorting bool
+}
+
+func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
+ var keys []string = make([]string, 0, len(entry.Data))
+ for k := range entry.Data {
+ keys = append(keys, k)
+ }
+
+ if !f.DisableSorting {
+ sort.Strings(keys)
+ }
+
+ b := &bytes.Buffer{}
+
+ prefixFieldClashes(entry.Data)
+
+ isColorTerminal := isTerminal && (runtime.GOOS != "windows")
+ isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
+
+ timestampFormat := f.TimestampFormat
+ if timestampFormat == "" {
+ timestampFormat = DefaultTimestampFormat
+ }
+ if isColored {
+ f.printColored(b, entry, keys, timestampFormat)
+ } else {
+ if !f.DisableTimestamp {
+ f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
+ }
+ f.appendKeyValue(b, "level", entry.Level.String())
+ if entry.Message != "" {
+ f.appendKeyValue(b, "msg", entry.Message)
+ }
+ for _, key := range keys {
+ f.appendKeyValue(b, key, entry.Data[key])
+ }
+ }
+
+ b.WriteByte('\n')
+ return b.Bytes(), nil
+}
+
+func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
+ var levelColor int
+ switch entry.Level {
+ case DebugLevel:
+ levelColor = gray
+ case WarnLevel:
+ levelColor = yellow
+ case ErrorLevel, FatalLevel, PanicLevel:
+ levelColor = red
+ default:
+ levelColor = blue
+ }
+
+ levelText := strings.ToUpper(entry.Level.String())[0:4]
+
+ if !f.FullTimestamp {
+ fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
+ } else {
+ fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
+ }
+ for _, k := range keys {
+ v := entry.Data[k]
+ fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
+ }
+}
+
+func needsQuoting(text string) bool {
+ for _, ch := range text {
+ if !((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') ||
+ ch == '-' || ch == '.') {
+ return false
+ }
+ }
+ return true
+}
+
+func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
+
+ b.WriteString(key)
+ b.WriteByte('=')
+
+ switch value := value.(type) {
+ case string:
+ if needsQuoting(value) {
+ b.WriteString(value)
+ } else {
+ fmt.Fprintf(b, "%q", value)
+ }
+ case error:
+ errmsg := value.Error()
+ if needsQuoting(errmsg) {
+ b.WriteString(errmsg)
+ } else {
+ fmt.Fprintf(b, "%q", value)
+ }
+ default:
+ fmt.Fprint(b, value)
+ }
+
+ b.WriteByte(' ')
+}
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/text_formatter_test.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/text_formatter_test.go
new file mode 100644
index 00000000..e25a44f6
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/text_formatter_test.go
@@ -0,0 +1,61 @@
+package logrus
+
+import (
+ "bytes"
+ "errors"
+ "testing"
+ "time"
+)
+
+func TestQuoting(t *testing.T) {
+ tf := &TextFormatter{DisableColors: true}
+
+ checkQuoting := func(q bool, value interface{}) {
+ b, _ := tf.Format(WithField("test", value))
+ idx := bytes.Index(b, ([]byte)("test="))
+ cont := bytes.Contains(b[idx+5:], []byte{'"'})
+ if cont != q {
+ if q {
+ t.Errorf("quoting expected for: %#v", value)
+ } else {
+ t.Errorf("quoting not expected for: %#v", value)
+ }
+ }
+ }
+
+ checkQuoting(false, "abcd")
+ checkQuoting(false, "v1.0")
+ checkQuoting(false, "1234567890")
+ checkQuoting(true, "/foobar")
+ checkQuoting(true, "x y")
+ checkQuoting(true, "x,y")
+ checkQuoting(false, errors.New("invalid"))
+ checkQuoting(true, errors.New("invalid argument"))
+}
+
+func TestTimestampFormat(t *testing.T) {
+ checkTimeStr := func(format string) {
+ customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format}
+ customStr, _ := customFormatter.Format(WithField("test", "test"))
+ timeStart := bytes.Index(customStr, ([]byte)("time="))
+ timeEnd := bytes.Index(customStr, ([]byte)("level="))
+ timeStr := customStr[timeStart+5 : timeEnd-1]
+ if timeStr[0] == '"' && timeStr[len(timeStr)-1] == '"' {
+ timeStr = timeStr[1 : len(timeStr)-1]
+ }
+ if format == "" {
+ format = time.RFC3339
+ }
+ _, e := time.Parse(format, (string)(timeStr))
+ if e != nil {
+ t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e)
+ }
+ }
+
+ checkTimeStr("2006-01-02T15:04:05.000000000Z07:00")
+ checkTimeStr("Mon Jan _2 15:04:05 2006")
+ checkTimeStr("")
+}
+
+// TODO add tests for sorting etc., this requires a parser for the text
+// formatter output.
diff --git a/go/src/gosetup/vendor/github.com/Sirupsen/logrus/writer.go b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/writer.go
new file mode 100644
index 00000000..1e30b1c7
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/Sirupsen/logrus/writer.go
@@ -0,0 +1,31 @@
+package logrus
+
+import (
+ "bufio"
+ "io"
+ "runtime"
+)
+
+func (logger *Logger) Writer() *io.PipeWriter {
+ reader, writer := io.Pipe()
+
+ go logger.writerScanner(reader)
+ runtime.SetFinalizer(writer, writerFinalizer)
+
+ return writer
+}
+
+func (logger *Logger) writerScanner(reader *io.PipeReader) {
+ scanner := bufio.NewScanner(reader)
+ for scanner.Scan() {
+ logger.Print(scanner.Text())
+ }
+ if err := scanner.Err(); err != nil {
+ logger.Errorf("Error while reading from Writer: %s", err)
+ }
+ reader.Close()
+}
+
+func writerFinalizer(writer *io.PipeWriter) {
+ writer.Close()
+}
diff --git a/go/src/gosetup/vendor/github.com/docker/go-units/CONTRIBUTING.md b/go/src/gosetup/vendor/github.com/docker/go-units/CONTRIBUTING.md
new file mode 100644
index 00000000..9ea86d78
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/CONTRIBUTING.md
@@ -0,0 +1,67 @@
+# Contributing to go-units
+
+Want to hack on go-units? Awesome! Here are instructions to get you started.
+
+go-units is a part of the [Docker](https://www.docker.com) project, and follows
+the same rules and principles. If you're already familiar with the way
+Docker does things, you'll feel right at home.
+
+Otherwise, go read Docker's
+[contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md),
+[issue triaging](https://github.com/docker/docker/blob/master/project/ISSUE-TRIAGE.md),
+[review process](https://github.com/docker/docker/blob/master/project/REVIEWING.md) and
+[branches and tags](https://github.com/docker/docker/blob/master/project/BRANCHES-AND-TAGS.md).
+
+### Sign your work
+
+The sign-off is a simple line at the end of the explanation for the patch. Your
+signature certifies that you wrote the patch or otherwise have the right to pass
+it on as an open-source patch. The rules are pretty simple: if you can certify
+the below (from [developercertificate.org](http://developercertificate.org/)):
+
+```
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+660 York Street, Suite 102,
+San Francisco, CA 94110 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+(d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+```
+
+Then you just add a line to every git commit message:
+
+ Signed-off-by: Joe Smith
+
+Use your real name (sorry, no pseudonyms or anonymous contributions.)
+
+If you set your `user.name` and `user.email` git configs, you can sign your
+commit automatically with `git commit -s`.
diff --git a/go/src/gosetup/vendor/github.com/docker/go-units/LICENSE.code b/go/src/gosetup/vendor/github.com/docker/go-units/LICENSE.code
new file mode 100644
index 00000000..b55b37bc
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/LICENSE.code
@@ -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/go/src/gosetup/vendor/github.com/docker/go-units/LICENSE.docs b/go/src/gosetup/vendor/github.com/docker/go-units/LICENSE.docs
new file mode 100644
index 00000000..e26cd4fc
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/LICENSE.docs
@@ -0,0 +1,425 @@
+Attribution-ShareAlike 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+ Considerations for licensors: Our public licenses are
+ intended for use by those authorized to give the public
+ permission to use material in ways otherwise restricted by
+ copyright and certain other rights. Our licenses are
+ irrevocable. Licensors should read and understand the terms
+ and conditions of the license they choose before applying it.
+ Licensors should also secure all rights necessary before
+ applying our licenses so that the public can reuse the
+ material as expected. Licensors should clearly mark any
+ material not subject to the license. This includes other CC-
+ licensed material, or material used under an exception or
+ limitation to copyright. More considerations for licensors:
+ wiki.creativecommons.org/Considerations_for_licensors
+
+ Considerations for the public: By using one of our public
+ licenses, a licensor grants the public permission to use the
+ licensed material under specified terms and conditions. If
+ the licensor's permission is not necessary for any reason--for
+ example, because of any applicable exception or limitation to
+ copyright--then that use is not regulated by the license. Our
+ licenses grant only permissions under copyright and certain
+ other rights that a licensor has authority to grant. Use of
+ the licensed material may still be restricted for other
+ reasons, including because others have copyright or other
+ rights in the material. A licensor may make special requests,
+ such as asking that all changes be marked or described.
+ Although not required by our licenses, you are encouraged to
+ respect those requests where reasonable. More_considerations
+ for the public:
+ wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution-ShareAlike 4.0 International Public
+License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution-ShareAlike 4.0 International Public License ("Public
+License"). To the extent this Public License may be interpreted as a
+contract, You are granted the Licensed Rights in consideration of Your
+acceptance of these terms and conditions, and the Licensor grants You
+such rights in consideration of benefits the Licensor receives from
+making the Licensed Material available under these terms and
+conditions.
+
+
+Section 1 -- Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+ Rights that is derived from or based upon the Licensed Material
+ and in which the Licensed Material is translated, altered,
+ arranged, transformed, or otherwise modified in a manner requiring
+ permission under the Copyright and Similar Rights held by the
+ Licensor. For purposes of this Public License, where the Licensed
+ Material is a musical work, performance, or sound recording,
+ Adapted Material is always produced where the Licensed Material is
+ synched in timed relation with a moving image.
+
+ b. Adapter's License means the license You apply to Your Copyright
+ and Similar Rights in Your contributions to Adapted Material in
+ accordance with the terms and conditions of this Public License.
+
+ c. BY-SA Compatible License means a license listed at
+ creativecommons.org/compatiblelicenses, approved by Creative
+ Commons as essentially the equivalent of this Public License.
+
+ d. Copyright and Similar Rights means copyright and/or similar rights
+ closely related to copyright including, without limitation,
+ performance, broadcast, sound recording, and Sui Generis Database
+ Rights, without regard to how the rights are labeled or
+ categorized. For purposes of this Public License, the rights
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
+ Rights.
+
+ e. Effective Technological Measures means those measures that, in the
+ absence of proper authority, may not be circumvented under laws
+ fulfilling obligations under Article 11 of the WIPO Copyright
+ Treaty adopted on December 20, 1996, and/or similar international
+ agreements.
+
+ f. Exceptions and Limitations means fair use, fair dealing, and/or
+ any other exception or limitation to Copyright and Similar Rights
+ that applies to Your use of the Licensed Material.
+
+ g. License Elements means the license attributes listed in the name
+ of a Creative Commons Public License. The License Elements of this
+ Public License are Attribution and ShareAlike.
+
+ h. Licensed Material means the artistic or literary work, database,
+ or other material to which the Licensor applied this Public
+ License.
+
+ i. Licensed Rights means the rights granted to You subject to the
+ terms and conditions of this Public License, which are limited to
+ all Copyright and Similar Rights that apply to Your use of the
+ Licensed Material and that the Licensor has authority to license.
+
+ j. Licensor means the individual(s) or entity(ies) granting rights
+ under this Public License.
+
+ k. Share means to provide material to the public by any means or
+ process that requires permission under the Licensed Rights, such
+ as reproduction, public display, public performance, distribution,
+ dissemination, communication, or importation, and to make material
+ available to the public including in ways that members of the
+ public may access the material from a place and at a time
+ individually chosen by them.
+
+ l. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament and of
+ the Council of 11 March 1996 on the legal protection of databases,
+ as amended and/or succeeded, as well as other essentially
+ equivalent rights anywhere in the world.
+
+ m. You means the individual or entity exercising the Licensed Rights
+ under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+ a. License grant.
+
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You a worldwide, royalty-free,
+ non-sublicensable, non-exclusive, irrevocable license to
+ exercise the Licensed Rights in the Licensed Material to:
+
+ a. reproduce and Share the Licensed Material, in whole or
+ in part; and
+
+ b. produce, reproduce, and Share Adapted Material.
+
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
+ Exceptions and Limitations apply to Your use, this Public
+ License does not apply, and You do not need to comply with
+ its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section
+ 6(a).
+
+ 4. Media and formats; technical modifications allowed. The
+ Licensor authorizes You to exercise the Licensed Rights in
+ all media and formats whether now known or hereafter created,
+ and to make technical modifications necessary to do so. The
+ Licensor waives and/or agrees not to assert any right or
+ authority to forbid You from making technical modifications
+ necessary to exercise the Licensed Rights, including
+ technical modifications necessary to circumvent Effective
+ Technological Measures. For purposes of this Public License,
+ simply making modifications authorized by this Section 2(a)
+ (4) never produces Adapted Material.
+
+ 5. Downstream recipients.
+
+ a. Offer from the Licensor -- Licensed Material. Every
+ recipient of the Licensed Material automatically
+ receives an offer from the Licensor to exercise the
+ Licensed Rights under the terms and conditions of this
+ Public License.
+
+ b. Additional offer from the Licensor -- Adapted Material.
+ Every recipient of Adapted Material from You
+ automatically receives an offer from the Licensor to
+ exercise the Licensed Rights in the Adapted Material
+ under the conditions of the Adapter's License You apply.
+
+ c. No downstream restrictions. You may not offer or impose
+ any additional or different terms or conditions on, or
+ apply any Effective Technological Measures to, the
+ Licensed Material if doing so restricts exercise of the
+ Licensed Rights by any recipient of the Licensed
+ Material.
+
+ 6. No endorsement. Nothing in this Public License constitutes or
+ may be construed as permission to assert or imply that You
+ are, or that Your use of the Licensed Material is, connected
+ with, or sponsored, endorsed, or granted official status by,
+ the Licensor or others designated to receive attribution as
+ provided in Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+ 1. Moral rights, such as the right of integrity, are not
+ licensed under this Public License, nor are publicity,
+ privacy, and/or other similar personality rights; however, to
+ the extent possible, the Licensor waives and/or agrees not to
+ assert any such rights held by the Licensor to the limited
+ extent necessary to allow You to exercise the Licensed
+ Rights, but not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this
+ Public License.
+
+ 3. To the extent possible, the Licensor waives any right to
+ collect royalties from You for the exercise of the Licensed
+ Rights, whether directly or through a collecting society
+ under any voluntary or waivable statutory or compulsory
+ licensing scheme. In all other cases the Licensor expressly
+ reserves any right to collect such royalties.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+ a. Attribution.
+
+ 1. If You Share the Licensed Material (including in modified
+ form), You must:
+
+ a. retain the following if it is supplied by the Licensor
+ with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed
+ Material and any others designated to receive
+ attribution, in any reasonable manner requested by
+ the Licensor (including by pseudonym if
+ designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of
+ warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the
+ extent reasonably practicable;
+
+ b. indicate if You modified the Licensed Material and
+ retain an indication of any previous modifications; and
+
+ c. indicate the Licensed Material is licensed under this
+ Public License, and include the text of, or the URI or
+ hyperlink to, this Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
+ reasonable manner based on the medium, means, and context in
+ which You Share the Licensed Material. For example, it may be
+ reasonable to satisfy the conditions by providing a URI or
+ hyperlink to a resource that includes the required
+ information.
+
+ 3. If requested by the Licensor, You must remove any of the
+ information required by Section 3(a)(1)(A) to the extent
+ reasonably practicable.
+
+ b. ShareAlike.
+
+ In addition to the conditions in Section 3(a), if You Share
+ Adapted Material You produce, the following conditions also apply.
+
+ 1. The Adapter's License You apply must be a Creative Commons
+ license with the same License Elements, this version or
+ later, or a BY-SA Compatible License.
+
+ 2. You must include the text of, or the URI or hyperlink to, the
+ Adapter's License You apply. You may satisfy this condition
+ in any reasonable manner based on the medium, means, and
+ context in which You Share Adapted Material.
+
+ 3. You may not offer or impose any additional or different terms
+ or conditions on, or apply any Effective Technological
+ Measures to, Adapted Material that restrict exercise of the
+ rights granted under the Adapter's License You apply.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+ to extract, reuse, reproduce, and Share all or a substantial
+ portion of the contents of the database;
+
+ b. if You include all or a substantial portion of the database
+ contents in a database in which You have Sui Generis Database
+ Rights, then the database in which You have Sui Generis Database
+ Rights (but not its individual contents) is Adapted Material,
+
+ including for purposes of Section 3(b); and
+ c. You must comply with the conditions in Section 3(a) if You Share
+ all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+ c. The disclaimer of warranties and limitation of liability provided
+ above shall be interpreted in a manner that, to the extent
+ possible, most closely approximates an absolute disclaimer and
+ waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+ Similar Rights licensed here. However, if You fail to comply with
+ this Public License, then Your rights under this Public License
+ terminate automatically.
+
+ b. Where Your right to use the Licensed Material has terminated under
+ Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided
+ it is cured within 30 days of Your discovery of the
+ violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations
+ of this Public License.
+
+ c. For the avoidance of doubt, the Licensor may also offer the
+ Licensed Material under separate terms or conditions or stop
+ distributing the Licensed Material at any time; however, doing so
+ will not terminate this Public License.
+
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+ License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+ terms or conditions communicated by You unless expressly agreed.
+
+ b. Any arrangements, understandings, or agreements regarding the
+ Licensed Material not stated herein are separate from and
+ independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and
+ shall not be interpreted to, reduce, limit, restrict, or impose
+ conditions on any use of the Licensed Material that could lawfully
+ be made without permission under this Public License.
+
+ b. To the extent possible, if any provision of this Public License is
+ deemed unenforceable, it shall be automatically reformed to the
+ minimum extent necessary to make it enforceable. If the provision
+ cannot be reformed, it shall be severed from this Public License
+ without affecting the enforceability of the remaining terms and
+ conditions.
+
+ c. No term or condition of this Public License will be waived and no
+ failure to comply consented to unless expressly agreed to by the
+ Licensor.
+
+ d. Nothing in this Public License constitutes or may be interpreted
+ as a limitation upon, or waiver of, any privileges and immunities
+ that apply to the Licensor or You, including from the legal
+ processes of any jurisdiction or authority.
+
+
+=======================================================================
+
+Creative Commons is not a party to its public licenses.
+Notwithstanding, Creative Commons may elect to apply one of its public
+licenses to material it publishes and in those instances will be
+considered the "Licensor." Except for the limited purpose of indicating
+that material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the public
+licenses.
+
+Creative Commons may be contacted at creativecommons.org.
diff --git a/go/src/gosetup/vendor/github.com/docker/go-units/MAINTAINERS b/go/src/gosetup/vendor/github.com/docker/go-units/MAINTAINERS
new file mode 100644
index 00000000..477be8b2
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/MAINTAINERS
@@ -0,0 +1,27 @@
+# go-connections maintainers file
+#
+# This file describes who runs the docker/go-connections project and how.
+# This is a living document - if you see something out of date or missing, speak up!
+#
+# It is structured to be consumable by both humans and programs.
+# To extract its contents programmatically, use any TOML-compliant parser.
+#
+# This file is compiled into the MAINTAINERS file in docker/opensource.
+#
+[Org]
+ [Org."Core maintainers"]
+ people = [
+ "calavera",
+ ]
+
+[people]
+
+# A reference list of all people associated with the project.
+# All other sections should refer to people by their canonical key
+# in the people section.
+
+ # ADD YOURSELF HERE IN ALPHABETICAL ORDER
+ [people.calavera]
+ Name = "David Calavera"
+ Email = "david.calavera@gmail.com"
+ GitHub = "calavera"
diff --git a/go/src/gosetup/vendor/github.com/docker/go-units/README.md b/go/src/gosetup/vendor/github.com/docker/go-units/README.md
new file mode 100644
index 00000000..3ce4d79d
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/README.md
@@ -0,0 +1,18 @@
+[](https://godoc.org/github.com/docker/go-units)
+
+# Introduction
+
+go-units is a library to transform human friendly measurements into machine friendly values.
+
+## Usage
+
+See the [docs in godoc](https://godoc.org/github.com/docker/go-units) for examples and documentation.
+
+## Copyright and license
+
+Copyright © 2015 Docker, Inc. All rights reserved, except as follows. Code
+is released under the Apache 2.0 license. The README.md file, and files in the
+"docs" folder are licensed under the Creative Commons Attribution 4.0
+International License under the terms and conditions set forth in the file
+"LICENSE.docs". You may obtain a duplicate copy of the same license, titled
+CC-BY-SA-4.0, at http://creativecommons.org/licenses/by/4.0/.
diff --git a/go/src/gosetup/vendor/github.com/docker/go-units/circle.yml b/go/src/gosetup/vendor/github.com/docker/go-units/circle.yml
new file mode 100644
index 00000000..9043b354
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/circle.yml
@@ -0,0 +1,11 @@
+dependencies:
+ post:
+ # install golint
+ - go get github.com/golang/lint/golint
+
+test:
+ pre:
+ # run analysis before tests
+ - go vet ./...
+ - test -z "$(golint ./... | tee /dev/stderr)"
+ - test -z "$(gofmt -s -l . | tee /dev/stderr)"
diff --git a/go/src/gosetup/vendor/github.com/docker/go-units/duration.go b/go/src/gosetup/vendor/github.com/docker/go-units/duration.go
new file mode 100644
index 00000000..c219a8a9
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/duration.go
@@ -0,0 +1,33 @@
+// Package units provides helper function to parse and print size and time units
+// in human-readable format.
+package units
+
+import (
+ "fmt"
+ "time"
+)
+
+// HumanDuration returns a human-readable approximation of a duration
+// (eg. "About a minute", "4 hours ago", etc.).
+func HumanDuration(d time.Duration) string {
+ if seconds := int(d.Seconds()); seconds < 1 {
+ return "Less than a second"
+ } else if seconds < 60 {
+ return fmt.Sprintf("%d seconds", seconds)
+ } else if minutes := int(d.Minutes()); minutes == 1 {
+ return "About a minute"
+ } else if minutes < 60 {
+ return fmt.Sprintf("%d minutes", minutes)
+ } else if hours := int(d.Hours()); hours == 1 {
+ return "About an hour"
+ } else if hours < 48 {
+ return fmt.Sprintf("%d hours", hours)
+ } else if hours < 24*7*2 {
+ return fmt.Sprintf("%d days", hours/24)
+ } else if hours < 24*30*3 {
+ return fmt.Sprintf("%d weeks", hours/24/7)
+ } else if hours < 24*365*2 {
+ return fmt.Sprintf("%d months", hours/24/30)
+ }
+ return fmt.Sprintf("%d years", int(d.Hours())/24/365)
+}
diff --git a/go/src/gosetup/vendor/github.com/docker/go-units/duration_test.go b/go/src/gosetup/vendor/github.com/docker/go-units/duration_test.go
new file mode 100644
index 00000000..63baa515
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/duration_test.go
@@ -0,0 +1,81 @@
+package units
+
+import (
+ "fmt"
+ "testing"
+ "time"
+)
+
+func ExampleHumanDuration() {
+ fmt.Println(HumanDuration(450 * time.Millisecond))
+ fmt.Println(HumanDuration(47 * time.Second))
+ fmt.Println(HumanDuration(1 * time.Minute))
+ fmt.Println(HumanDuration(3 * time.Minute))
+ fmt.Println(HumanDuration(35 * time.Minute))
+ fmt.Println(HumanDuration(35*time.Minute + 40*time.Second))
+ fmt.Println(HumanDuration(1 * time.Hour))
+ fmt.Println(HumanDuration(1*time.Hour + 45*time.Minute))
+ fmt.Println(HumanDuration(3 * time.Hour))
+ fmt.Println(HumanDuration(3*time.Hour + 59*time.Minute))
+ fmt.Println(HumanDuration(3*time.Hour + 60*time.Minute))
+ fmt.Println(HumanDuration(24 * time.Hour))
+ fmt.Println(HumanDuration(24*time.Hour + 12*time.Hour))
+ fmt.Println(HumanDuration(2 * 24 * time.Hour))
+ fmt.Println(HumanDuration(7 * 24 * time.Hour))
+ fmt.Println(HumanDuration(13*24*time.Hour + 5*time.Hour))
+ fmt.Println(HumanDuration(2 * 7 * 24 * time.Hour))
+ fmt.Println(HumanDuration(2*7*24*time.Hour + 4*24*time.Hour))
+ fmt.Println(HumanDuration(3 * 7 * 24 * time.Hour))
+ fmt.Println(HumanDuration(4 * 7 * 24 * time.Hour))
+ fmt.Println(HumanDuration(4*7*24*time.Hour + 3*24*time.Hour))
+ fmt.Println(HumanDuration(1 * 30 * 24 * time.Hour))
+ fmt.Println(HumanDuration(1*30*24*time.Hour + 2*7*24*time.Hour))
+ fmt.Println(HumanDuration(2 * 30 * 24 * time.Hour))
+ fmt.Println(HumanDuration(3*30*24*time.Hour + 1*7*24*time.Hour))
+ fmt.Println(HumanDuration(5*30*24*time.Hour + 2*7*24*time.Hour))
+ fmt.Println(HumanDuration(13 * 30 * 24 * time.Hour))
+ fmt.Println(HumanDuration(23 * 30 * 24 * time.Hour))
+ fmt.Println(HumanDuration(24 * 30 * 24 * time.Hour))
+ fmt.Println(HumanDuration(24*30*24*time.Hour + 2*7*24*time.Hour))
+ fmt.Println(HumanDuration(3*365*24*time.Hour + 2*30*24*time.Hour))
+}
+
+func TestHumanDuration(t *testing.T) {
+ // Useful duration abstractions
+ day := 24 * time.Hour
+ week := 7 * day
+ month := 30 * day
+ year := 365 * day
+
+ assertEquals(t, "Less than a second", HumanDuration(450*time.Millisecond))
+ assertEquals(t, "47 seconds", HumanDuration(47*time.Second))
+ assertEquals(t, "About a minute", HumanDuration(1*time.Minute))
+ assertEquals(t, "3 minutes", HumanDuration(3*time.Minute))
+ assertEquals(t, "35 minutes", HumanDuration(35*time.Minute))
+ assertEquals(t, "35 minutes", HumanDuration(35*time.Minute+40*time.Second))
+ assertEquals(t, "About an hour", HumanDuration(1*time.Hour))
+ assertEquals(t, "About an hour", HumanDuration(1*time.Hour+45*time.Minute))
+ assertEquals(t, "3 hours", HumanDuration(3*time.Hour))
+ assertEquals(t, "3 hours", HumanDuration(3*time.Hour+59*time.Minute))
+ assertEquals(t, "4 hours", HumanDuration(3*time.Hour+60*time.Minute))
+ assertEquals(t, "24 hours", HumanDuration(24*time.Hour))
+ assertEquals(t, "36 hours", HumanDuration(1*day+12*time.Hour))
+ assertEquals(t, "2 days", HumanDuration(2*day))
+ assertEquals(t, "7 days", HumanDuration(7*day))
+ assertEquals(t, "13 days", HumanDuration(13*day+5*time.Hour))
+ assertEquals(t, "2 weeks", HumanDuration(2*week))
+ assertEquals(t, "2 weeks", HumanDuration(2*week+4*day))
+ assertEquals(t, "3 weeks", HumanDuration(3*week))
+ assertEquals(t, "4 weeks", HumanDuration(4*week))
+ assertEquals(t, "4 weeks", HumanDuration(4*week+3*day))
+ assertEquals(t, "4 weeks", HumanDuration(1*month))
+ assertEquals(t, "6 weeks", HumanDuration(1*month+2*week))
+ assertEquals(t, "8 weeks", HumanDuration(2*month))
+ assertEquals(t, "3 months", HumanDuration(3*month+1*week))
+ assertEquals(t, "5 months", HumanDuration(5*month+2*week))
+ assertEquals(t, "13 months", HumanDuration(13*month))
+ assertEquals(t, "23 months", HumanDuration(23*month))
+ assertEquals(t, "24 months", HumanDuration(24*month))
+ assertEquals(t, "2 years", HumanDuration(24*month+2*week))
+ assertEquals(t, "3 years", HumanDuration(3*year+2*month))
+}
diff --git a/go/src/gosetup/vendor/github.com/docker/go-units/size.go b/go/src/gosetup/vendor/github.com/docker/go-units/size.go
new file mode 100644
index 00000000..989edd29
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/size.go
@@ -0,0 +1,95 @@
+package units
+
+import (
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+// See: http://en.wikipedia.org/wiki/Binary_prefix
+const (
+ // Decimal
+
+ KB = 1000
+ MB = 1000 * KB
+ GB = 1000 * MB
+ TB = 1000 * GB
+ PB = 1000 * TB
+
+ // Binary
+
+ KiB = 1024
+ MiB = 1024 * KiB
+ GiB = 1024 * MiB
+ TiB = 1024 * GiB
+ PiB = 1024 * TiB
+)
+
+type unitMap map[string]int64
+
+var (
+ decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB}
+ binaryMap = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB}
+ sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[bB]?$`)
+)
+
+var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
+var binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
+
+// CustomSize returns a human-readable approximation of a size
+// using custom format.
+func CustomSize(format string, size float64, base float64, _map []string) string {
+ i := 0
+ for size >= base {
+ size = size / base
+ i++
+ }
+ return fmt.Sprintf(format, size, _map[i])
+}
+
+// HumanSize returns a human-readable approximation of a size
+// capped at 4 valid numbers (eg. "2.746 MB", "796 KB").
+func HumanSize(size float64) string {
+ return CustomSize("%.4g %s", size, 1000.0, decimapAbbrs)
+}
+
+// BytesSize returns a human-readable size in bytes, kibibytes,
+// mebibytes, gibibytes, or tebibytes (eg. "44kiB", "17MiB").
+func BytesSize(size float64) string {
+ return CustomSize("%.4g %s", size, 1024.0, binaryAbbrs)
+}
+
+// FromHumanSize returns an integer from a human-readable specification of a
+// size using SI standard (eg. "44kB", "17MB").
+func FromHumanSize(size string) (int64, error) {
+ return parseSize(size, decimalMap)
+}
+
+// RAMInBytes parses a human-readable string representing an amount of RAM
+// in bytes, kibibytes, mebibytes, gibibytes, or tebibytes and
+// returns the number of bytes, or -1 if the string is unparseable.
+// Units are case-insensitive, and the 'b' suffix is optional.
+func RAMInBytes(size string) (int64, error) {
+ return parseSize(size, binaryMap)
+}
+
+// Parses the human-readable size string into the amount it represents.
+func parseSize(sizeStr string, uMap unitMap) (int64, error) {
+ matches := sizeRegex.FindStringSubmatch(sizeStr)
+ if len(matches) != 4 {
+ return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
+ }
+
+ size, err := strconv.ParseFloat(matches[1], 64)
+ if err != nil {
+ return -1, err
+ }
+
+ unitPrefix := strings.ToLower(matches[3])
+ if mul, ok := uMap[unitPrefix]; ok {
+ size *= float64(mul)
+ }
+
+ return int64(size), nil
+}
diff --git a/go/src/gosetup/vendor/github.com/docker/go-units/size_test.go b/go/src/gosetup/vendor/github.com/docker/go-units/size_test.go
new file mode 100644
index 00000000..003bc89a
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/size_test.go
@@ -0,0 +1,163 @@
+package units
+
+import (
+ "fmt"
+ "reflect"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+func ExampleBytesSize() {
+ fmt.Println(BytesSize(1024))
+ fmt.Println(BytesSize(1024 * 1024))
+ fmt.Println(BytesSize(1048576))
+ fmt.Println(BytesSize(2 * MiB))
+ fmt.Println(BytesSize(3.42 * GiB))
+ fmt.Println(BytesSize(5.372 * TiB))
+ fmt.Println(BytesSize(2.22 * PiB))
+}
+
+func ExampleHumanSize() {
+ fmt.Println(HumanSize(1000))
+ fmt.Println(HumanSize(1024))
+ fmt.Println(HumanSize(1000000))
+ fmt.Println(HumanSize(1048576))
+ fmt.Println(HumanSize(2 * MB))
+ fmt.Println(HumanSize(float64(3.42 * GB)))
+ fmt.Println(HumanSize(float64(5.372 * TB)))
+ fmt.Println(HumanSize(float64(2.22 * PB)))
+}
+
+func ExampleFromHumanSize() {
+ fmt.Println(FromHumanSize("32"))
+ fmt.Println(FromHumanSize("32b"))
+ fmt.Println(FromHumanSize("32B"))
+ fmt.Println(FromHumanSize("32k"))
+ fmt.Println(FromHumanSize("32K"))
+ fmt.Println(FromHumanSize("32kb"))
+ fmt.Println(FromHumanSize("32Kb"))
+ fmt.Println(FromHumanSize("32Mb"))
+ fmt.Println(FromHumanSize("32Gb"))
+ fmt.Println(FromHumanSize("32Tb"))
+ fmt.Println(FromHumanSize("32Pb"))
+}
+
+func ExampleRAMInBytes() {
+ fmt.Println(RAMInBytes("32"))
+ fmt.Println(RAMInBytes("32b"))
+ fmt.Println(RAMInBytes("32B"))
+ fmt.Println(RAMInBytes("32k"))
+ fmt.Println(RAMInBytes("32K"))
+ fmt.Println(RAMInBytes("32kb"))
+ fmt.Println(RAMInBytes("32Kb"))
+ fmt.Println(RAMInBytes("32Mb"))
+ fmt.Println(RAMInBytes("32Gb"))
+ fmt.Println(RAMInBytes("32Tb"))
+ fmt.Println(RAMInBytes("32Pb"))
+ fmt.Println(RAMInBytes("32PB"))
+ fmt.Println(RAMInBytes("32P"))
+}
+
+func TestBytesSize(t *testing.T) {
+ assertEquals(t, "1 KiB", BytesSize(1024))
+ assertEquals(t, "1 MiB", BytesSize(1024*1024))
+ assertEquals(t, "1 MiB", BytesSize(1048576))
+ assertEquals(t, "2 MiB", BytesSize(2*MiB))
+ assertEquals(t, "3.42 GiB", BytesSize(3.42*GiB))
+ assertEquals(t, "5.372 TiB", BytesSize(5.372*TiB))
+ assertEquals(t, "2.22 PiB", BytesSize(2.22*PiB))
+}
+
+func TestHumanSize(t *testing.T) {
+ assertEquals(t, "1 kB", HumanSize(1000))
+ assertEquals(t, "1.024 kB", HumanSize(1024))
+ assertEquals(t, "1 MB", HumanSize(1000000))
+ assertEquals(t, "1.049 MB", HumanSize(1048576))
+ assertEquals(t, "2 MB", HumanSize(2*MB))
+ assertEquals(t, "3.42 GB", HumanSize(float64(3.42*GB)))
+ assertEquals(t, "5.372 TB", HumanSize(float64(5.372*TB)))
+ assertEquals(t, "2.22 PB", HumanSize(float64(2.22*PB)))
+}
+
+func TestFromHumanSize(t *testing.T) {
+ assertSuccessEquals(t, 32, FromHumanSize, "32")
+ assertSuccessEquals(t, 32, FromHumanSize, "32b")
+ assertSuccessEquals(t, 32, FromHumanSize, "32B")
+ assertSuccessEquals(t, 32*KB, FromHumanSize, "32k")
+ assertSuccessEquals(t, 32*KB, FromHumanSize, "32K")
+ assertSuccessEquals(t, 32*KB, FromHumanSize, "32kb")
+ assertSuccessEquals(t, 32*KB, FromHumanSize, "32Kb")
+ assertSuccessEquals(t, 32*MB, FromHumanSize, "32Mb")
+ assertSuccessEquals(t, 32*GB, FromHumanSize, "32Gb")
+ assertSuccessEquals(t, 32*TB, FromHumanSize, "32Tb")
+ assertSuccessEquals(t, 32*PB, FromHumanSize, "32Pb")
+
+ assertSuccessEquals(t, 32.5*KB, FromHumanSize, "32.5kB")
+ assertSuccessEquals(t, 32.5*KB, FromHumanSize, "32.5 kB")
+ assertSuccessEquals(t, 32, FromHumanSize, "32.5 B")
+
+ assertError(t, FromHumanSize, "")
+ assertError(t, FromHumanSize, "hello")
+ assertError(t, FromHumanSize, "-32")
+ assertError(t, FromHumanSize, ".3kB")
+ assertError(t, FromHumanSize, " 32 ")
+ assertError(t, FromHumanSize, "32m b")
+ assertError(t, FromHumanSize, "32bm")
+}
+
+func TestRAMInBytes(t *testing.T) {
+ assertSuccessEquals(t, 32, RAMInBytes, "32")
+ assertSuccessEquals(t, 32, RAMInBytes, "32b")
+ assertSuccessEquals(t, 32, RAMInBytes, "32B")
+ assertSuccessEquals(t, 32*KiB, RAMInBytes, "32k")
+ assertSuccessEquals(t, 32*KiB, RAMInBytes, "32K")
+ assertSuccessEquals(t, 32*KiB, RAMInBytes, "32kb")
+ assertSuccessEquals(t, 32*KiB, RAMInBytes, "32Kb")
+ assertSuccessEquals(t, 32*MiB, RAMInBytes, "32Mb")
+ assertSuccessEquals(t, 32*GiB, RAMInBytes, "32Gb")
+ assertSuccessEquals(t, 32*TiB, RAMInBytes, "32Tb")
+ assertSuccessEquals(t, 32*PiB, RAMInBytes, "32Pb")
+ assertSuccessEquals(t, 32*PiB, RAMInBytes, "32PB")
+ assertSuccessEquals(t, 32*PiB, RAMInBytes, "32P")
+
+ assertSuccessEquals(t, 32, RAMInBytes, "32.3")
+ tmp := 32.3 * MiB
+ assertSuccessEquals(t, int64(tmp), RAMInBytes, "32.3 mb")
+
+ assertError(t, RAMInBytes, "")
+ assertError(t, RAMInBytes, "hello")
+ assertError(t, RAMInBytes, "-32")
+ assertError(t, RAMInBytes, " 32 ")
+ assertError(t, RAMInBytes, "32m b")
+ assertError(t, RAMInBytes, "32bm")
+}
+
+func assertEquals(t *testing.T, expected, actual interface{}) {
+ if expected != actual {
+ t.Errorf("Expected '%v' but got '%v'", expected, actual)
+ }
+}
+
+// func that maps to the parse function signatures as testing abstraction
+type parseFn func(string) (int64, error)
+
+// Define 'String()' for pretty-print
+func (fn parseFn) String() string {
+ fnName := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
+ return fnName[strings.LastIndex(fnName, ".")+1:]
+}
+
+func assertSuccessEquals(t *testing.T, expected int64, fn parseFn, arg string) {
+ res, err := fn(arg)
+ if err != nil || res != expected {
+ t.Errorf("%s(\"%s\") -> expected '%d' but got '%d' with error '%v'", fn, arg, expected, res, err)
+ }
+}
+
+func assertError(t *testing.T, fn parseFn, arg string) {
+ res, err := fn(arg)
+ if err == nil && res != -1 {
+ t.Errorf("%s(\"%s\") -> expected error but got '%d'", fn, arg, res)
+ }
+}
diff --git a/go/src/gosetup/vendor/github.com/docker/go-units/ulimit.go b/go/src/gosetup/vendor/github.com/docker/go-units/ulimit.go
new file mode 100644
index 00000000..5ac7fd82
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/ulimit.go
@@ -0,0 +1,118 @@
+package units
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// Ulimit is a human friendly version of Rlimit.
+type Ulimit struct {
+ Name string
+ Hard int64
+ Soft int64
+}
+
+// Rlimit specifies the resource limits, such as max open files.
+type Rlimit struct {
+ Type int `json:"type,omitempty"`
+ Hard uint64 `json:"hard,omitempty"`
+ Soft uint64 `json:"soft,omitempty"`
+}
+
+const (
+ // magic numbers for making the syscall
+ // some of these are defined in the syscall package, but not all.
+ // Also since Windows client doesn't get access to the syscall package, need to
+ // define these here
+ rlimitAs = 9
+ rlimitCore = 4
+ rlimitCPU = 0
+ rlimitData = 2
+ rlimitFsize = 1
+ rlimitLocks = 10
+ rlimitMemlock = 8
+ rlimitMsgqueue = 12
+ rlimitNice = 13
+ rlimitNofile = 7
+ rlimitNproc = 6
+ rlimitRss = 5
+ rlimitRtprio = 14
+ rlimitRttime = 15
+ rlimitSigpending = 11
+ rlimitStack = 3
+)
+
+var ulimitNameMapping = map[string]int{
+ //"as": rlimitAs, // Disabled since this doesn't seem usable with the way Docker inits a container.
+ "core": rlimitCore,
+ "cpu": rlimitCPU,
+ "data": rlimitData,
+ "fsize": rlimitFsize,
+ "locks": rlimitLocks,
+ "memlock": rlimitMemlock,
+ "msgqueue": rlimitMsgqueue,
+ "nice": rlimitNice,
+ "nofile": rlimitNofile,
+ "nproc": rlimitNproc,
+ "rss": rlimitRss,
+ "rtprio": rlimitRtprio,
+ "rttime": rlimitRttime,
+ "sigpending": rlimitSigpending,
+ "stack": rlimitStack,
+}
+
+// ParseUlimit parses and returns a Ulimit from the specified string.
+func ParseUlimit(val string) (*Ulimit, error) {
+ parts := strings.SplitN(val, "=", 2)
+ if len(parts) != 2 {
+ return nil, fmt.Errorf("invalid ulimit argument: %s", val)
+ }
+
+ if _, exists := ulimitNameMapping[parts[0]]; !exists {
+ return nil, fmt.Errorf("invalid ulimit type: %s", parts[0])
+ }
+
+ var (
+ soft int64
+ hard = &soft // default to soft in case no hard was set
+ temp int64
+ err error
+ )
+ switch limitVals := strings.Split(parts[1], ":"); len(limitVals) {
+ case 2:
+ temp, err = strconv.ParseInt(limitVals[1], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ hard = &temp
+ fallthrough
+ case 1:
+ soft, err = strconv.ParseInt(limitVals[0], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ default:
+ return nil, fmt.Errorf("too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1])
+ }
+
+ if soft > *hard {
+ return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: %d > %d", soft, *hard)
+ }
+
+ return &Ulimit{Name: parts[0], Soft: soft, Hard: *hard}, nil
+}
+
+// GetRlimit returns the RLimit corresponding to Ulimit.
+func (u *Ulimit) GetRlimit() (*Rlimit, error) {
+ t, exists := ulimitNameMapping[u.Name]
+ if !exists {
+ return nil, fmt.Errorf("invalid ulimit name %s", u.Name)
+ }
+
+ return &Rlimit{Type: t, Soft: uint64(u.Soft), Hard: uint64(u.Hard)}, nil
+}
+
+func (u *Ulimit) String() string {
+ return fmt.Sprintf("%s=%d:%d", u.Name, u.Soft, u.Hard)
+}
diff --git a/go/src/gosetup/vendor/github.com/docker/go-units/ulimit_test.go b/go/src/gosetup/vendor/github.com/docker/go-units/ulimit_test.go
new file mode 100644
index 00000000..3e7f10fc
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/docker/go-units/ulimit_test.go
@@ -0,0 +1,74 @@
+package units
+
+import (
+ "fmt"
+ "strconv"
+ "testing"
+)
+
+func ExampleParseUlimit() {
+ fmt.Println(ParseUlimit("nofile=512:1024"))
+ fmt.Println(ParseUlimit("nofile=1024"))
+ fmt.Println(ParseUlimit("cpu=2:4"))
+ fmt.Println(ParseUlimit("cpu=6"))
+}
+
+func TestParseUlimitValid(t *testing.T) {
+ u1 := &Ulimit{"nofile", 1024, 512}
+ if u2, _ := ParseUlimit("nofile=512:1024"); *u1 != *u2 {
+ t.Fatalf("expected %q, but got %q", u1, u2)
+ }
+}
+
+func TestParseUlimitInvalidLimitType(t *testing.T) {
+ if _, err := ParseUlimit("notarealtype=1024:1024"); err == nil {
+ t.Fatalf("expected error on invalid ulimit type")
+ }
+}
+
+func TestParseUlimitBadFormat(t *testing.T) {
+ if _, err := ParseUlimit("nofile:1024:1024"); err == nil {
+ t.Fatal("expected error on bad syntax")
+ }
+
+ if _, err := ParseUlimit("nofile"); err == nil {
+ t.Fatal("expected error on bad syntax")
+ }
+
+ if _, err := ParseUlimit("nofile="); err == nil {
+ t.Fatal("expected error on bad syntax")
+ }
+ if _, err := ParseUlimit("nofile=:"); err == nil {
+ t.Fatal("expected error on bad syntax")
+ }
+ if _, err := ParseUlimit("nofile=:1024"); err == nil {
+ t.Fatal("expected error on bad syntax")
+ }
+}
+
+func TestParseUlimitHardLessThanSoft(t *testing.T) {
+ if _, err := ParseUlimit("nofile=1024:1"); err == nil {
+ t.Fatal("expected error on hard limit less than soft limit")
+ }
+}
+
+func TestParseUlimitInvalidValueType(t *testing.T) {
+ if _, err := ParseUlimit("nofile=asdf"); err == nil {
+ t.Fatal("expected error on bad value type, but got no error")
+ } else if _, ok := err.(*strconv.NumError); !ok {
+ t.Fatalf("expected error on bad value type, but got `%s`", err)
+ }
+
+ if _, err := ParseUlimit("nofile=1024:asdf"); err == nil {
+ t.Fatal("expected error on bad value type, but got no error")
+ } else if _, ok := err.(*strconv.NumError); !ok {
+ t.Fatalf("expected error on bad value type, but got `%s`", err)
+ }
+}
+
+func TestUlimitStringOutput(t *testing.T) {
+ u := &Ulimit{"nofile", 1024, 512}
+ if s := u.String(); s != "nofile=512:1024" {
+ t.Fatal("expected String to return nofile=512:1024, but got", s)
+ }
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/LICENSE b/go/src/gosetup/vendor/github.com/samalba/dockerclient/LICENSE
new file mode 100644
index 00000000..00e1edb9
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/LICENSE
@@ -0,0 +1,202 @@
+Apache License
+ Version 2.0, January 2004
+ http://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
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2014 Sam Alba
+
+ 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
+
+ http://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/go/src/gosetup/vendor/github.com/samalba/dockerclient/README.md b/go/src/gosetup/vendor/github.com/samalba/dockerclient/README.md
new file mode 100644
index 00000000..6cad9bd3
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/README.md
@@ -0,0 +1,98 @@
+Docker client library in Go
+===========================
+[](http://godoc.org/github.com/samalba/dockerclient)
+
+Well maintained docker client library.
+
+# How to use it?
+
+Here is an example showing how to use it:
+
+```go
+package main
+
+import (
+ "github.com/samalba/dockerclient"
+ "log"
+ "time"
+ "os"
+)
+
+// Callback used to listen to Docker's events
+func eventCallback(event *dockerclient.Event, ec chan error, args ...interface{}) {
+ log.Printf("Received event: %#v\n", *event)
+}
+
+func main() {
+ // Init the client
+ docker, _ := dockerclient.NewDockerClient("unix:///var/run/docker.sock", nil)
+
+ // Get only running containers
+ containers, err := docker.ListContainers(false, false, "")
+ if err != nil {
+ log.Fatal(err)
+ }
+ for _, c := range containers {
+ log.Println(c.Id, c.Names)
+ }
+
+ // Inspect the first container returned
+ if len(containers) > 0 {
+ id := containers[0].Id
+ info, _ := docker.InspectContainer(id)
+ log.Println(info)
+ }
+
+ // Build a docker image
+ // some.tar contains the build context (Dockerfile any any files it needs to add/copy)
+ dockerBuildContext, err := os.Open("some.tar")
+ defer dockerBuildContext.Close()
+ buildImageConfig := &dockerclient.BuildImage{
+ Context: dockerBuildContext,
+ RepoName: "your_image_name",
+ SuppressOutput: false,
+ }
+ reader, err := docker.BuildImage(buildImageConfig)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Create a container
+ containerConfig := &dockerclient.ContainerConfig{
+ Image: "ubuntu:14.04",
+ Cmd: []string{"bash"},
+ AttachStdin: true,
+ Tty: true}
+ containerId, err := docker.CreateContainer(containerConfig, "foobar", nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Start the container
+ hostConfig := &dockerclient.HostConfig{}
+ err = docker.StartContainer(containerId, hostConfig)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Stop the container (with 5 seconds timeout)
+ docker.StopContainer(containerId, 5)
+
+ // Listen to events
+ docker.StartMonitorEvents(eventCallback, nil)
+
+ // Hold the execution to look at the events coming
+ time.Sleep(3600 * time.Second)
+}
+```
+
+# Maintainers
+
+List of people you can ping for feedback on Pull Requests or any questions.
+
+- [Sam Alba](https://github.com/samalba)
+- [Michael Crosby](https://github.com/crosbymichael)
+- [Andrea Luzzardi](https://github.com/aluzzardi)
+- [Victor Vieux](https://github.com/vieux)
+- [Evan Hazlett](https://github.com/ehazlett)
+- [Donald Huang](https://github.com/donhcd)
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/auth.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/auth.go
new file mode 100644
index 00000000..7c0a67f7
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/auth.go
@@ -0,0 +1,39 @@
+package dockerclient
+
+import (
+ "bytes"
+ "encoding/base64"
+ "encoding/json"
+)
+
+// AuthConfig hold parameters for authenticating with the docker registry
+type AuthConfig struct {
+ Username string `json:"username,omitempty"`
+ Password string `json:"password,omitempty"`
+ Email string `json:"email,omitempty"`
+ RegistryToken string `json:"registrytoken,omitempty"`
+}
+
+// encode the auth configuration struct into base64 for the X-Registry-Auth header
+func (c *AuthConfig) encode() (string, error) {
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(c); err != nil {
+ return "", err
+ }
+ return base64.URLEncoding.EncodeToString(buf.Bytes()), nil
+}
+
+// ConfigFile holds parameters for authenticating during a BuildImage request
+type ConfigFile struct {
+ Configs map[string]AuthConfig `json:"configs,omitempty"`
+ rootPath string
+}
+
+// encode the configuration struct into base64 for the X-Registry-Config header
+func (c *ConfigFile) encode() (string, error) {
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(c); err != nil {
+ return "", err
+ }
+ return base64.URLEncoding.EncodeToString(buf.Bytes()), nil
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/auth_test.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/auth_test.go
new file mode 100755
index 00000000..99801b22
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/auth_test.go
@@ -0,0 +1,15 @@
+package dockerclient
+
+import (
+ "testing"
+)
+
+func TestAuthEncode(t *testing.T) {
+ a := AuthConfig{Username: "foo", Password: "password", Email: "bar@baz.com"}
+ expected := "eyJ1c2VybmFtZSI6ImZvbyIsInBhc3N3b3JkIjoicGFzc3dvcmQiLCJlbWFpbCI6ImJhckBiYXouY29tIn0K"
+ got, _ := a.encode()
+
+ if expected != got {
+ t.Errorf("testAuthEncode failed. Expected [%s] got [%s]", expected, got)
+ }
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/dockerclient.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/dockerclient.go
new file mode 100644
index 00000000..51a00b29
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/dockerclient.go
@@ -0,0 +1,1001 @@
+package dockerclient
+
+import (
+ "bytes"
+ "crypto/tls"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+ "sync/atomic"
+ "time"
+)
+
+var _ Client = (*DockerClient)(nil)
+
+const (
+ // APIVersion is currently hardcoded to v1.15
+ // TODO: bump the API version or allow users to choose which API version to
+ // use the client with. The current value does not make sense for many
+ // methods, such as ContainerStats, StartMonitorStats, and StopAllMonitorStats
+ // (v1.17) and
+ // ListVolumes, {Remove,Create}Volume, ListNetworks,
+ // {Inspect,Create,Connect,Disconnect,Remove}Network (v1.21)
+ APIVersion = "v1.15"
+)
+
+var (
+ ErrImageNotFound = errors.New("Image not found")
+ ErrNotFound = errors.New("Not found")
+ ErrConnectionRefused = errors.New("Cannot connect to the docker engine endpoint")
+
+ defaultTimeout = 30 * time.Second
+)
+
+type DockerClient struct {
+ URL *url.URL
+ HTTPClient *http.Client
+ TLSConfig *tls.Config
+ monitorStats int32
+ eventStopChan chan (struct{})
+}
+
+type Error struct {
+ StatusCode int
+ Status string
+ msg string
+}
+
+func (e Error) Error() string {
+ return fmt.Sprintf("%s: %s", e.Status, e.msg)
+}
+
+func NewDockerClient(daemonUrl string, tlsConfig *tls.Config) (*DockerClient, error) {
+ return NewDockerClientTimeout(daemonUrl, tlsConfig, time.Duration(defaultTimeout), nil)
+}
+
+func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout time.Duration, setUserTimeout tcpFunc) (*DockerClient, error) {
+ u, err := url.Parse(daemonUrl)
+ if err != nil {
+ return nil, err
+ }
+ if u.Scheme == "" || u.Scheme == "tcp" {
+ if tlsConfig == nil {
+ u.Scheme = "http"
+ } else {
+ u.Scheme = "https"
+ }
+ }
+ httpClient := newHTTPClient(u, tlsConfig, timeout, setUserTimeout)
+ return &DockerClient{u, httpClient, tlsConfig, 0, nil}, nil
+}
+
+func (client *DockerClient) doRequest(method string, path string, body []byte, headers map[string]string) ([]byte, error) {
+ b := bytes.NewBuffer(body)
+
+ reader, err := client.doStreamRequest(method, path, b, headers)
+ if err != nil {
+ return nil, err
+ }
+
+ defer reader.Close()
+ data, err := ioutil.ReadAll(reader)
+ if err != nil {
+ return nil, err
+ }
+ return data, nil
+}
+
+func (client *DockerClient) doStreamRequest(method string, path string, in io.Reader, headers map[string]string) (io.ReadCloser, error) {
+ if (method == "POST" || method == "PUT") && in == nil {
+ in = bytes.NewReader(nil)
+ }
+ req, err := http.NewRequest(method, client.URL.String()+path, in)
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Add("Content-Type", "application/json")
+ if headers != nil {
+ for header, value := range headers {
+ req.Header.Add(header, value)
+ }
+ }
+ resp, err := client.HTTPClient.Do(req)
+ if err != nil {
+ if !strings.Contains(err.Error(), "connection refused") && client.TLSConfig == nil {
+ return nil, fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err)
+ }
+ if strings.Contains(err.Error(), "connection refused") {
+ return nil, ErrConnectionRefused
+ }
+ return nil, err
+ }
+ if resp.StatusCode == 404 {
+ defer resp.Body.Close()
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, ErrNotFound
+ }
+ if len(data) > 0 {
+ // check if is image not found error
+ if strings.Index(string(data), "No such image") != -1 {
+ return nil, ErrImageNotFound
+ }
+ return nil, errors.New(string(data))
+ }
+ return nil, ErrNotFound
+ }
+ if resp.StatusCode >= 400 {
+ defer resp.Body.Close()
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+ return nil, Error{StatusCode: resp.StatusCode, Status: resp.Status, msg: string(data)}
+ }
+
+ return resp.Body, nil
+}
+
+func (client *DockerClient) Info() (*Info, error) {
+ uri := fmt.Sprintf("/%s/info", APIVersion)
+ data, err := client.doRequest("GET", uri, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ ret := &Info{}
+ err = json.Unmarshal(data, &ret)
+ if err != nil {
+ return nil, err
+ }
+ return ret, nil
+}
+
+func (client *DockerClient) ListContainers(all bool, size bool, filters string) ([]Container, error) {
+ argAll := 0
+ if all == true {
+ argAll = 1
+ }
+ showSize := 0
+ if size == true {
+ showSize = 1
+ }
+ uri := fmt.Sprintf("/%s/containers/json?all=%d&size=%d", APIVersion, argAll, showSize)
+
+ if filters != "" {
+ uri += "&filters=" + filters
+ }
+
+ data, err := client.doRequest("GET", uri, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ ret := []Container{}
+ err = json.Unmarshal(data, &ret)
+ if err != nil {
+ return nil, err
+ }
+ return ret, nil
+}
+
+func (client *DockerClient) InspectContainer(id string) (*ContainerInfo, error) {
+ uri := fmt.Sprintf("/%s/containers/%s/json", APIVersion, id)
+ data, err := client.doRequest("GET", uri, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ info := &ContainerInfo{}
+ err = json.Unmarshal(data, info)
+ if err != nil {
+ return nil, err
+ }
+ return info, nil
+}
+
+func (client *DockerClient) CreateContainer(config *ContainerConfig, name string, auth *AuthConfig) (string, error) {
+ data, err := json.Marshal(config)
+ if err != nil {
+ return "", err
+ }
+ uri := fmt.Sprintf("/%s/containers/create", APIVersion)
+ if name != "" {
+ v := url.Values{}
+ v.Set("name", name)
+ uri = fmt.Sprintf("%s?%s", uri, v.Encode())
+ }
+ headers := map[string]string{}
+ if auth != nil {
+ encoded_auth, err := auth.encode()
+ if err != nil {
+ return "", err
+ }
+ headers["X-Registry-Auth"] = encoded_auth
+ }
+ data, err = client.doRequest("POST", uri, data, headers)
+ if err != nil {
+ return "", err
+ }
+ result := &RespContainersCreate{}
+ err = json.Unmarshal(data, result)
+ if err != nil {
+ return "", fmt.Errorf(string(data))
+ }
+ return result.Id, nil
+}
+
+func (client *DockerClient) ContainerLogs(id string, options *LogOptions) (io.ReadCloser, error) {
+ v := url.Values{}
+ v.Add("follow", strconv.FormatBool(options.Follow))
+ v.Add("stdout", strconv.FormatBool(options.Stdout))
+ v.Add("stderr", strconv.FormatBool(options.Stderr))
+ v.Add("timestamps", strconv.FormatBool(options.Timestamps))
+ if options.Tail > 0 {
+ v.Add("tail", strconv.FormatInt(options.Tail, 10))
+ }
+
+ uri := fmt.Sprintf("/%s/containers/%s/logs?%s", APIVersion, id, v.Encode())
+ req, err := http.NewRequest("GET", client.URL.String()+uri, nil)
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Add("Content-Type", "application/json")
+ resp, err := client.HTTPClient.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ return resp.Body, nil
+}
+
+func (client *DockerClient) ContainerChanges(id string) ([]*ContainerChanges, error) {
+ uri := fmt.Sprintf("/%s/containers/%s/changes", APIVersion, id)
+ data, err := client.doRequest("GET", uri, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ changes := []*ContainerChanges{}
+ err = json.Unmarshal(data, &changes)
+ if err != nil {
+ return nil, err
+ }
+ return changes, nil
+}
+
+func (client *DockerClient) ContainerStats(id string, stopChan <-chan struct{}) (<-chan StatsOrError, error) {
+ uri := fmt.Sprintf("/%s/containers/%s/stats", APIVersion, id)
+ resp, err := client.HTTPClient.Get(client.URL.String() + uri)
+ if err != nil {
+ return nil, err
+ }
+
+ decode := func(decoder *json.Decoder) decodingResult {
+ var containerStats Stats
+ if err := decoder.Decode(&containerStats); err != nil {
+ return decodingResult{err: err}
+ } else {
+ return decodingResult{result: containerStats}
+ }
+ }
+ decodingResultChan := client.readJSONStream(resp.Body, decode, stopChan)
+ statsOrErrorChan := make(chan StatsOrError)
+ go func() {
+ for decodingResult := range decodingResultChan {
+ stats, _ := decodingResult.result.(Stats)
+ statsOrErrorChan <- StatsOrError{
+ Stats: stats,
+ Error: decodingResult.err,
+ }
+ }
+ close(statsOrErrorChan)
+ }()
+ return statsOrErrorChan, nil
+}
+
+func (client *DockerClient) readJSONStream(stream io.ReadCloser, decode func(*json.Decoder) decodingResult, stopChan <-chan struct{}) <-chan decodingResult {
+ resultChan := make(chan decodingResult)
+
+ go func() {
+ decodeChan := make(chan decodingResult)
+
+ go func() {
+ decoder := json.NewDecoder(stream)
+ for {
+ decodeResult := decode(decoder)
+ decodeChan <- decodeResult
+ if decodeResult.err != nil {
+ close(decodeChan)
+ return
+ }
+ }
+ }()
+
+ defer close(resultChan)
+
+ for {
+ select {
+ case <-stopChan:
+ stream.Close()
+ for range decodeChan {
+ }
+ return
+ case decodeResult := <-decodeChan:
+ resultChan <- decodeResult
+ if decodeResult.err != nil {
+ stream.Close()
+ return
+ }
+ }
+ }
+
+ }()
+
+ return resultChan
+}
+
+func (client *DockerClient) ExecCreate(config *ExecConfig) (string, error) {
+ data, err := json.Marshal(config)
+ if err != nil {
+ return "", err
+ }
+ uri := fmt.Sprintf("/%s/containers/%s/exec", APIVersion, config.Container)
+ resp, err := client.doRequest("POST", uri, data, nil)
+ if err != nil {
+ return "", err
+ }
+ var createExecResp struct {
+ Id string
+ }
+ if err = json.Unmarshal(resp, &createExecResp); err != nil {
+ return "", err
+ }
+ return createExecResp.Id, nil
+}
+
+func (client *DockerClient) ExecStart(id string, config *ExecConfig) error {
+ data, err := json.Marshal(config)
+ if err != nil {
+ return err
+ }
+
+ uri := fmt.Sprintf("/%s/exec/%s/start", APIVersion, id)
+ if _, err := client.doRequest("POST", uri, data, nil); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (client *DockerClient) ExecResize(id string, width, height int) error {
+ v := url.Values{}
+
+ w := strconv.Itoa(width)
+ h := strconv.Itoa(height)
+
+ v.Set("w", w)
+ v.Set("h", h)
+
+ uri := fmt.Sprintf("/%s/exec/%s/resize?%s", APIVersion, id, v.Encode())
+ if _, err := client.doRequest("POST", client.URL.String()+uri, nil, nil); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (client *DockerClient) AttachContainer(id string, options *AttachOptions) (io.ReadCloser, error) {
+ v := url.Values{}
+ if options != nil {
+ if options.Logs {
+ v.Set("logs", "1")
+ }
+ if options.Stream {
+ v.Set("stream", "1")
+ }
+ if options.Stdin {
+ v.Set("stdin", "1")
+ }
+ if options.Stdout {
+ v.Set("stdout", "1")
+ }
+ if options.Stderr {
+ v.Set("stderr", "1")
+ }
+ }
+ uri := fmt.Sprintf("/%s/containers/%s/attach?%s", APIVersion, id, v.Encode())
+ return client.doStreamRequest("POST", uri, nil, nil)
+}
+
+func (client *DockerClient) StartContainer(id string, config *HostConfig) error {
+ data, err := json.Marshal(config)
+ if err != nil {
+ return err
+ }
+ uri := fmt.Sprintf("/%s/containers/%s/start", APIVersion, id)
+ _, err = client.doRequest("POST", uri, data, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (client *DockerClient) StopContainer(id string, timeout int) error {
+ uri := fmt.Sprintf("/%s/containers/%s/stop?t=%d", APIVersion, id, timeout)
+ _, err := client.doRequest("POST", uri, nil, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (client *DockerClient) RestartContainer(id string, timeout int) error {
+ uri := fmt.Sprintf("/%s/containers/%s/restart?t=%d", APIVersion, id, timeout)
+ _, err := client.doRequest("POST", uri, nil, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (client *DockerClient) KillContainer(id, signal string) error {
+ uri := fmt.Sprintf("/%s/containers/%s/kill?signal=%s", APIVersion, id, signal)
+ _, err := client.doRequest("POST", uri, nil, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (client *DockerClient) Wait(id string) <-chan WaitResult {
+ ch := make(chan WaitResult)
+ uri := fmt.Sprintf("/%s/containers/%s/wait", APIVersion, id)
+
+ go func() {
+ data, err := client.doRequest("POST", uri, nil, nil)
+ if err != nil {
+ ch <- WaitResult{ExitCode: -1, Error: err}
+ return
+ }
+
+ var result struct {
+ StatusCode int `json:"StatusCode"`
+ }
+ err = json.Unmarshal(data, &result)
+ ch <- WaitResult{ExitCode: result.StatusCode, Error: err}
+ }()
+ return ch
+}
+
+func (client *DockerClient) MonitorEvents(options *MonitorEventsOptions, stopChan <-chan struct{}) (<-chan EventOrError, error) {
+ v := url.Values{}
+ if options != nil {
+ if options.Since != 0 {
+ v.Add("since", strconv.Itoa(options.Since))
+ }
+ if options.Until != 0 {
+ v.Add("until", strconv.Itoa(options.Until))
+ }
+ if options.Filters != nil {
+ filterMap := make(map[string][]string)
+ if len(options.Filters.Event) > 0 {
+ filterMap["event"] = []string{options.Filters.Event}
+ }
+ if len(options.Filters.Image) > 0 {
+ filterMap["image"] = []string{options.Filters.Image}
+ }
+ if len(options.Filters.Container) > 0 {
+ filterMap["container"] = []string{options.Filters.Container}
+ }
+ if len(filterMap) > 0 {
+ filterJSONBytes, err := json.Marshal(filterMap)
+ if err != nil {
+ return nil, err
+ }
+ v.Add("filters", string(filterJSONBytes))
+ }
+ }
+ }
+ uri := fmt.Sprintf("%s/%s/events?%s", client.URL.String(), APIVersion, v.Encode())
+ resp, err := client.HTTPClient.Get(uri)
+ if err != nil {
+ return nil, err
+ }
+
+ decode := func(decoder *json.Decoder) decodingResult {
+ var event Event
+ if err := decoder.Decode(&event); err != nil {
+ return decodingResult{err: err}
+ } else {
+ return decodingResult{result: event}
+ }
+ }
+ decodingResultChan := client.readJSONStream(resp.Body, decode, stopChan)
+ eventOrErrorChan := make(chan EventOrError)
+ go func() {
+ for decodingResult := range decodingResultChan {
+ event, _ := decodingResult.result.(Event)
+ eventOrErrorChan <- EventOrError{
+ Event: event,
+ Error: decodingResult.err,
+ }
+ }
+ close(eventOrErrorChan)
+ }()
+ return eventOrErrorChan, nil
+}
+
+func (client *DockerClient) StartMonitorEvents(cb Callback, ec chan error, args ...interface{}) {
+ client.eventStopChan = make(chan struct{})
+
+ go func() {
+ eventErrChan, err := client.MonitorEvents(nil, client.eventStopChan)
+ if err != nil {
+ if ec != nil {
+ ec <- err
+ }
+ return
+ }
+
+ for e := range eventErrChan {
+ if e.Error != nil {
+ if ec != nil {
+ ec <- e.Error
+ }
+ return
+ }
+ cb(&e.Event, ec, args...)
+ }
+ }()
+}
+
+func (client *DockerClient) StopAllMonitorEvents() {
+ if client.eventStopChan == nil {
+ return
+ }
+ close(client.eventStopChan)
+}
+
+func (client *DockerClient) StartMonitorStats(id string, cb StatCallback, ec chan error, args ...interface{}) {
+ atomic.StoreInt32(&client.monitorStats, 1)
+ go client.getStats(id, cb, ec, args...)
+}
+
+func (client *DockerClient) getStats(id string, cb StatCallback, ec chan error, args ...interface{}) {
+ uri := fmt.Sprintf("%s/%s/containers/%s/stats", client.URL.String(), APIVersion, id)
+ resp, err := client.HTTPClient.Get(uri)
+ if err != nil {
+ ec <- err
+ return
+ }
+ defer resp.Body.Close()
+
+ dec := json.NewDecoder(resp.Body)
+ for atomic.LoadInt32(&client.monitorStats) > 0 {
+ var stats *Stats
+ if err := dec.Decode(&stats); err != nil {
+ ec <- err
+ return
+ }
+ cb(id, stats, ec, args...)
+ }
+}
+
+func (client *DockerClient) StopAllMonitorStats() {
+ atomic.StoreInt32(&client.monitorStats, 0)
+}
+
+func (client *DockerClient) TagImage(nameOrID string, repo string, tag string, force bool) error {
+ v := url.Values{}
+ v.Set("repo", repo)
+ v.Set("tag", tag)
+ if force {
+ v.Set("force", "1")
+ }
+ uri := fmt.Sprintf("/%s/images/%s/tag?%s", APIVersion, nameOrID, v.Encode())
+ if _, err := client.doRequest("POST", uri, nil, nil); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (client *DockerClient) Version() (*Version, error) {
+ uri := fmt.Sprintf("/%s/version", APIVersion)
+ data, err := client.doRequest("GET", uri, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ version := &Version{}
+ err = json.Unmarshal(data, version)
+ if err != nil {
+ return nil, err
+ }
+ return version, nil
+}
+
+func (client *DockerClient) PushImage(name string, tag string, auth *AuthConfig) error {
+ v := url.Values{}
+ if tag != "" {
+ v.Set("tag", tag)
+ }
+ uri := fmt.Sprintf("/%s/images/%s/push?%s", APIVersion, url.QueryEscape(name), v.Encode())
+ req, err := http.NewRequest("POST", client.URL.String()+uri, nil)
+ if auth != nil {
+ if encodedAuth, err := auth.encode(); err != nil {
+ return err
+ } else {
+ req.Header.Add("X-Registry-Auth", encodedAuth)
+ }
+ }
+ resp, err := client.HTTPClient.Do(req)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+ var finalObj map[string]interface{}
+ for decoder := json.NewDecoder(resp.Body); err == nil; err = decoder.Decode(&finalObj) {
+ }
+ if err != io.EOF {
+ return err
+ }
+ if err, ok := finalObj["error"]; ok {
+ return fmt.Errorf("%v", err)
+ }
+ return nil
+}
+
+func (client *DockerClient) PullImage(name string, auth *AuthConfig) error {
+ v := url.Values{}
+ v.Set("fromImage", name)
+ uri := fmt.Sprintf("/%s/images/create?%s", APIVersion, v.Encode())
+ req, err := http.NewRequest("POST", client.URL.String()+uri, nil)
+ if auth != nil {
+ encoded_auth, err := auth.encode()
+ if err != nil {
+ return err
+ }
+ req.Header.Add("X-Registry-Auth", encoded_auth)
+ }
+ resp, err := client.HTTPClient.Do(req)
+ if err != nil {
+ return err
+ }
+
+ defer resp.Body.Close()
+ if resp.StatusCode == 404 {
+ return ErrNotFound
+ }
+ if resp.StatusCode >= 400 {
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return err
+ }
+ return fmt.Errorf("%s", string(data))
+ }
+
+ var finalObj map[string]interface{}
+ for decoder := json.NewDecoder(resp.Body); err == nil; err = decoder.Decode(&finalObj) {
+ }
+ if err != io.EOF {
+ return err
+ }
+ if err, ok := finalObj["error"]; ok {
+ return fmt.Errorf("%v", err)
+ }
+ return nil
+}
+
+func (client *DockerClient) InspectImage(id string) (*ImageInfo, error) {
+ uri := fmt.Sprintf("/%s/images/%s/json", APIVersion, id)
+ data, err := client.doRequest("GET", uri, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ info := &ImageInfo{}
+ err = json.Unmarshal(data, info)
+ if err != nil {
+ return nil, err
+ }
+ return info, nil
+}
+
+func (client *DockerClient) LoadImage(reader io.Reader) error {
+ uri := fmt.Sprintf("/%s/images/load", APIVersion)
+ _, err := client.doStreamRequest("POST", uri, reader, nil)
+ return err
+}
+
+func (client *DockerClient) RemoveContainer(id string, force, volumes bool) error {
+ argForce := 0
+ argVolumes := 0
+ if force == true {
+ argForce = 1
+ }
+ if volumes == true {
+ argVolumes = 1
+ }
+ args := fmt.Sprintf("force=%d&v=%d", argForce, argVolumes)
+ uri := fmt.Sprintf("/%s/containers/%s?%s", APIVersion, id, args)
+ _, err := client.doRequest("DELETE", uri, nil, nil)
+ return err
+}
+
+func (client *DockerClient) ListImages(all bool) ([]*Image, error) {
+ argAll := 0
+ if all {
+ argAll = 1
+ }
+ uri := fmt.Sprintf("/%s/images/json?all=%d", APIVersion, argAll)
+ data, err := client.doRequest("GET", uri, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ var images []*Image
+ if err := json.Unmarshal(data, &images); err != nil {
+ return nil, err
+ }
+ return images, nil
+}
+
+func (client *DockerClient) RemoveImage(name string, force bool) ([]*ImageDelete, error) {
+ argForce := 0
+ if force {
+ argForce = 1
+ }
+
+ args := fmt.Sprintf("force=%d", argForce)
+ uri := fmt.Sprintf("/%s/images/%s?%s", APIVersion, name, args)
+ data, err := client.doRequest("DELETE", uri, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ var imageDelete []*ImageDelete
+ if err := json.Unmarshal(data, &imageDelete); err != nil {
+ return nil, err
+ }
+ return imageDelete, nil
+}
+
+func (client *DockerClient) SearchImages(query, registry string, auth *AuthConfig) ([]ImageSearch, error) {
+ term := query
+ if registry != "" {
+ term = registry + "/" + term
+ }
+ uri := fmt.Sprintf("/%s/images/search?term=%s", APIVersion, term)
+ headers := map[string]string{}
+ if auth != nil {
+ if encodedAuth, err := auth.encode(); err != nil {
+ return nil, err
+ } else {
+ headers["X-Registry-Auth"] = encodedAuth
+ }
+ }
+ data, err := client.doRequest("GET", uri, nil, headers)
+ if err != nil {
+ return nil, err
+ }
+ var imageSearches []ImageSearch
+ if err := json.Unmarshal(data, &imageSearches); err != nil {
+ return nil, err
+ }
+ return imageSearches, nil
+}
+
+func (client *DockerClient) PauseContainer(id string) error {
+ uri := fmt.Sprintf("/%s/containers/%s/pause", APIVersion, id)
+ _, err := client.doRequest("POST", uri, nil, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+func (client *DockerClient) UnpauseContainer(id string) error {
+ uri := fmt.Sprintf("/%s/containers/%s/unpause", APIVersion, id)
+ _, err := client.doRequest("POST", uri, nil, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (client *DockerClient) RenameContainer(oldName string, newName string) error {
+ uri := fmt.Sprintf("/containers/%s/rename?name=%s", oldName, newName)
+ _, err := client.doRequest("POST", uri, nil, nil)
+ return err
+}
+
+func (client *DockerClient) ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error) {
+ var fromSrc string
+ v := &url.Values{}
+ if source == "" {
+ fromSrc = "-"
+ } else {
+ fromSrc = source
+ }
+
+ v.Set("fromSrc", fromSrc)
+ v.Set("repo", repository)
+ if tag != "" {
+ v.Set("tag", tag)
+ }
+
+ var in io.Reader
+ if fromSrc == "-" {
+ in = tar
+ }
+ return client.doStreamRequest("POST", "/images/create?"+v.Encode(), in, nil)
+}
+
+func (client *DockerClient) BuildImage(image *BuildImage) (io.ReadCloser, error) {
+ v := url.Values{}
+
+ if image.DockerfileName != "" {
+ v.Set("dockerfile", image.DockerfileName)
+ }
+ if image.RepoName != "" {
+ v.Set("t", image.RepoName)
+ }
+ if image.RemoteURL != "" {
+ v.Set("remote", image.RemoteURL)
+ }
+ if image.NoCache {
+ v.Set("nocache", "1")
+ }
+ if image.Pull {
+ v.Set("pull", "1")
+ }
+ if image.Remove {
+ v.Set("rm", "1")
+ } else {
+ v.Set("rm", "0")
+ }
+ if image.ForceRemove {
+ v.Set("forcerm", "1")
+ }
+ if image.SuppressOutput {
+ v.Set("q", "1")
+ }
+
+ v.Set("memory", strconv.FormatInt(image.Memory, 10))
+ v.Set("memswap", strconv.FormatInt(image.MemorySwap, 10))
+ v.Set("cpushares", strconv.FormatInt(image.CpuShares, 10))
+ v.Set("cpuperiod", strconv.FormatInt(image.CpuPeriod, 10))
+ v.Set("cpuquota", strconv.FormatInt(image.CpuQuota, 10))
+ v.Set("cpusetcpus", image.CpuSetCpus)
+ v.Set("cpusetmems", image.CpuSetMems)
+ v.Set("cgroupparent", image.CgroupParent)
+ if image.BuildArgs != nil {
+ buildArgsJSON, err := json.Marshal(image.BuildArgs)
+ if err != nil {
+ return nil, err
+ }
+ v.Set("buildargs", string(buildArgsJSON))
+ }
+
+ headers := make(map[string]string)
+ if image.Config != nil {
+ encoded_config, err := image.Config.encode()
+ if err != nil {
+ return nil, err
+ }
+ headers["X-Registry-Config"] = encoded_config
+ }
+ if image.Context != nil {
+ headers["Content-Type"] = "application/tar"
+ }
+
+ uri := fmt.Sprintf("/%s/build?%s", APIVersion, v.Encode())
+ return client.doStreamRequest("POST", uri, image.Context, headers)
+}
+
+func (client *DockerClient) ListVolumes() ([]*Volume, error) {
+ uri := fmt.Sprintf("/%s/volumes", APIVersion)
+ data, err := client.doRequest("GET", uri, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ var volumesList VolumesListResponse
+ if err := json.Unmarshal(data, &volumesList); err != nil {
+ return nil, err
+ }
+ return volumesList.Volumes, nil
+}
+
+func (client *DockerClient) RemoveVolume(name string) error {
+ uri := fmt.Sprintf("/%s/volumes/%s", APIVersion, name)
+ _, err := client.doRequest("DELETE", uri, nil, nil)
+ return err
+}
+
+func (client *DockerClient) CreateVolume(request *VolumeCreateRequest) (*Volume, error) {
+ data, err := json.Marshal(request)
+ if err != nil {
+ return nil, err
+ }
+ uri := fmt.Sprintf("/%s/volumes/create", APIVersion)
+ data, err = client.doRequest("POST", uri, data, nil)
+ if err != nil {
+ return nil, err
+ }
+ volume := &Volume{}
+ err = json.Unmarshal(data, volume)
+ return volume, err
+}
+
+func (client *DockerClient) ListNetworks(filters string) ([]*NetworkResource, error) {
+ uri := fmt.Sprintf("/%s/networks", APIVersion)
+
+ if filters != "" {
+ uri += "&filters=" + filters
+ }
+
+ data, err := client.doRequest("GET", uri, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ ret := []*NetworkResource{}
+ err = json.Unmarshal(data, &ret)
+ if err != nil {
+ return nil, err
+ }
+ return ret, nil
+}
+
+func (client *DockerClient) InspectNetwork(id string) (*NetworkResource, error) {
+ uri := fmt.Sprintf("/%s/networks/%s", APIVersion, id)
+
+ data, err := client.doRequest("GET", uri, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ ret := &NetworkResource{}
+ err = json.Unmarshal(data, ret)
+ if err != nil {
+ return nil, err
+ }
+
+ return ret, nil
+}
+
+func (client *DockerClient) CreateNetwork(config *NetworkCreate) (*NetworkCreateResponse, error) {
+ data, err := json.Marshal(config)
+ if err != nil {
+ return nil, err
+ }
+ uri := fmt.Sprintf("/%s/networks/create", APIVersion)
+ data, err = client.doRequest("POST", uri, data, nil)
+ if err != nil {
+ return nil, err
+ }
+ ret := &NetworkCreateResponse{}
+ err = json.Unmarshal(data, ret)
+ return ret, nil
+}
+
+func (client *DockerClient) ConnectNetwork(id, container string) error {
+ data, err := json.Marshal(NetworkConnect{Container: container})
+ if err != nil {
+ return err
+ }
+ uri := fmt.Sprintf("/%s/networks/%s/connect", APIVersion, id)
+ _, err = client.doRequest("POST", uri, data, nil)
+ return err
+}
+
+func (client *DockerClient) DisconnectNetwork(id, container string, force bool) error {
+ data, err := json.Marshal(NetworkDisconnect{Container: container, Force: force})
+ if err != nil {
+ return err
+ }
+ uri := fmt.Sprintf("/%s/networks/%s/disconnect", APIVersion, id)
+ _, err = client.doRequest("POST", uri, data, nil)
+ return err
+}
+
+func (client *DockerClient) RemoveNetwork(id string) error {
+ uri := fmt.Sprintf("/%s/networks/%s", APIVersion, id)
+ _, err := client.doRequest("DELETE", uri, nil, nil)
+ return err
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/dockerclient_test.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/dockerclient_test.go
new file mode 100644
index 00000000..7c7b3f59
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/dockerclient_test.go
@@ -0,0 +1,320 @@
+package dockerclient
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/docker/docker/pkg/stdcopy"
+)
+
+func assertEqual(t *testing.T, a interface{}, b interface{}, message string) {
+ if a == b {
+ return
+ }
+ if len(message) == 0 {
+ message = fmt.Sprintf("%v != %v", a, b)
+ }
+ t.Fatal(message)
+}
+
+func testDockerClient(t *testing.T) *DockerClient {
+ client, err := NewDockerClient(testHTTPServer.URL, nil)
+ if err != nil {
+ t.Fatal("Cannot init the docker client")
+ }
+ return client
+}
+
+func ExampleDockerClient_AttachContainer() {
+ docker, err := NewDockerClient("unix:///var/run/docker.sock", nil)
+ if err != nil {
+ panic(err)
+ }
+ cID, err := docker.CreateContainer(&ContainerConfig{
+ Cmd: []string{"echo", "hi"},
+ Image: "busybox",
+ }, "", nil)
+ if err != nil {
+ panic(err)
+ }
+ done := make(chan struct{})
+ if body, err := docker.AttachContainer(cID, &AttachOptions{
+ Stream: true,
+ Stdout: true,
+ }); err != nil {
+ panic(err)
+ } else {
+ go func() {
+ defer body.Close()
+ if _, err := stdcopy.StdCopy(os.Stdout, os.Stderr, body); err != nil {
+ panic(err)
+ }
+ close(done)
+ }()
+ }
+
+ if err := docker.StartContainer(cID, nil); err != nil {
+ panic(err)
+ }
+ <-done
+}
+
+func TestInfo(t *testing.T) {
+ client := testDockerClient(t)
+ info, err := client.Info()
+ if err != nil {
+ t.Fatal("Cannot get server info")
+ }
+ assertEqual(t, info.Images, int64(1), "")
+ assertEqual(t, info.Containers, int64(2), "")
+}
+
+func TestKillContainer(t *testing.T) {
+ client := testDockerClient(t)
+ if err := client.KillContainer("23132acf2ac", "5"); err != nil {
+ t.Fatal("cannot kill container: %s", err)
+ }
+}
+
+func TestWait(t *testing.T) {
+ client := testDockerClient(t)
+
+ // This provokes an error on the server.
+ select {
+ case wr := <-client.Wait("1234"):
+ assertEqual(t, wr.ExitCode, int(-1), "")
+ case <-time.After(2 * time.Second):
+ t.Fatal("Timed out!")
+ }
+
+ // Valid case.
+ select {
+ case wr := <-client.Wait("valid-id"):
+ assertEqual(t, wr.ExitCode, int(0), "")
+ case <-time.After(2 * time.Second):
+ t.Fatal("Timed out!")
+ }
+}
+
+func TestPullImage(t *testing.T) {
+ client := testDockerClient(t)
+ err := client.PullImage("busybox", nil)
+ if err != nil {
+ t.Fatal("unable to pull busybox")
+ }
+
+ err = client.PullImage("haproxy", nil)
+ if err != nil {
+ t.Fatal("unable to pull haproxy")
+ }
+
+ err = client.PullImage("wrongimg", nil)
+ if err == nil {
+ t.Fatal("should return error when it fails to pull wrongimg")
+ }
+}
+
+func TestListContainers(t *testing.T) {
+ client := testDockerClient(t)
+ containers, err := client.ListContainers(true, false, "")
+ if err != nil {
+ t.Fatal("cannot get containers: %s", err)
+ }
+ assertEqual(t, len(containers), 1, "")
+ cnt := containers[0]
+ assertEqual(t, cnt.SizeRw, int64(0), "")
+}
+
+func TestContainerChanges(t *testing.T) {
+ client := testDockerClient(t)
+ changes, err := client.ContainerChanges("foobar")
+ if err != nil {
+ t.Fatal("cannot get container changes: %s", err)
+ }
+ assertEqual(t, len(changes), 3, "unexpected number of changes")
+ c := changes[0]
+ assertEqual(t, c.Path, "/dev", "unexpected")
+ assertEqual(t, c.Kind, 0, "unexpected")
+}
+
+func TestListContainersWithSize(t *testing.T) {
+ client := testDockerClient(t)
+ containers, err := client.ListContainers(true, true, "")
+ if err != nil {
+ t.Fatal("cannot get containers: %s", err)
+ }
+ assertEqual(t, len(containers), 1, "")
+ cnt := containers[0]
+ assertEqual(t, cnt.SizeRw, int64(123), "")
+}
+
+func TestListContainersWithFilters(t *testing.T) {
+ client := testDockerClient(t)
+ containers, err := client.ListContainers(true, true, "{'id':['332375cfbc23edb921a21026314c3497674ba8bdcb2c85e0e65ebf2017f688ce']}")
+ if err != nil {
+ t.Fatal("cannot get containers: %s", err)
+ }
+ assertEqual(t, len(containers), 1, "")
+
+ containers, err = client.ListContainers(true, true, "{'id':['332375cfbc23edb921a21026314c3497674ba8bdcb2c85e0e65ebf2017f688cf']}")
+ if err != nil {
+ t.Fatal("cannot get containers: %s", err)
+ }
+ assertEqual(t, len(containers), 0, "")
+}
+
+func TestContainerLogs(t *testing.T) {
+ client := testDockerClient(t)
+ containerId := "foobar"
+ logOptions := &LogOptions{
+ Follow: true,
+ Stdout: true,
+ Stderr: true,
+ Timestamps: true,
+ Tail: 10,
+ }
+ logsReader, err := client.ContainerLogs(containerId, logOptions)
+ if err != nil {
+ t.Fatal("cannot read logs from server")
+ }
+
+ stdoutBuffer := new(bytes.Buffer)
+ stderrBuffer := new(bytes.Buffer)
+ if _, err = stdcopy.StdCopy(stdoutBuffer, stderrBuffer, logsReader); err != nil {
+ t.Fatal("cannot read logs from logs reader")
+ }
+ stdoutLogs := strings.TrimSpace(stdoutBuffer.String())
+ stderrLogs := strings.TrimSpace(stderrBuffer.String())
+ stdoutLogLines := strings.Split(stdoutLogs, "\n")
+ stderrLogLines := strings.Split(stderrLogs, "\n")
+ if len(stdoutLogLines) != 5 {
+ t.Fatalf("wrong number of stdout logs: len=%d", len(stdoutLogLines))
+ }
+ if len(stderrLogLines) != 5 {
+ t.Fatalf("wrong number of stderr logs: len=%d", len(stdoutLogLines))
+ }
+ for i, line := range stdoutLogLines {
+ expectedSuffix := fmt.Sprintf("Z line %d", 41+2*i)
+ if !strings.HasSuffix(line, expectedSuffix) {
+ t.Fatalf("expected stdout log line \"%s\" to end with \"%s\"", line, expectedSuffix)
+ }
+ }
+ for i, line := range stderrLogLines {
+ expectedSuffix := fmt.Sprintf("Z line %d", 40+2*i)
+ if !strings.HasSuffix(line, expectedSuffix) {
+ t.Fatalf("expected stderr log line \"%s\" to end with \"%s\"", line, expectedSuffix)
+ }
+ }
+}
+
+func TestContainerStats(t *testing.T) {
+ client := testDockerClient(t)
+ var expectedContainerStats Stats
+ if err := json.Unmarshal([]byte(statsResp), &expectedContainerStats); err != nil {
+ t.Fatalf("cannot parse expected resp: %s", err.Error())
+ }
+ containerIds := []string{"foobar", "foo"}
+ expectedResults := [][]StatsOrError{
+ {{Stats: expectedContainerStats}, {Error: fmt.Errorf("invalid character 'i' looking for beginning of value")}},
+ {{Stats: expectedContainerStats}, {Stats: expectedContainerStats}},
+ }
+
+ for i := range containerIds {
+ t.Logf("on outer iter %d\n", i)
+ stopChan := make(chan struct{})
+ statsOrErrorChan, err := client.ContainerStats(containerIds[i], stopChan)
+ if err != nil {
+ t.Fatalf("cannot get stats from server: %s", err.Error())
+ }
+
+ for j, expectedResult := range expectedResults[i] {
+ t.Logf("on iter %d\n", j)
+ containerStatsOrError := <-statsOrErrorChan
+ if containerStatsOrError.Error != nil {
+ if expectedResult.Error == nil {
+ t.Fatalf("index %d, got unexpected error %v", j, containerStatsOrError.Error)
+ } else if containerStatsOrError.Error.Error() == expectedResult.Error.Error() {
+ // continue so that we don't try to
+ // compare error values directly
+ continue
+ } else {
+ t.Fatalf("index %d, expected error %q but got %q", j, expectedResult.Error, containerStatsOrError.Error)
+ }
+ }
+ if !reflect.DeepEqual(containerStatsOrError, expectedResult) {
+ t.Fatalf("index %d, got:\n%#v\nexpected:\n%#v", j, containerStatsOrError, expectedResult)
+ }
+ t.Logf("done with iter %d\n", j)
+ }
+ close(stopChan)
+ t.Logf("done with outer iter %d\n", i)
+ }
+}
+
+func TestMonitorEvents(t *testing.T) {
+ client := testDockerClient(t)
+ decoder := json.NewDecoder(bytes.NewBufferString(eventsResp))
+ var expectedEvents []Event
+ for {
+ var event Event
+ if err := decoder.Decode(&event); err != nil {
+ if err == io.EOF {
+ break
+ } else {
+ t.Fatalf("cannot parse expected resp: %s", err.Error())
+ }
+ } else {
+ expectedEvents = append(expectedEvents, event)
+ }
+ }
+
+ // test passing stop chan
+ stopChan := make(chan struct{})
+ eventInfoChan, err := client.MonitorEvents(nil, stopChan)
+ if err != nil {
+ t.Fatalf("cannot get events from server: %s", err.Error())
+ }
+
+ eventInfo := <-eventInfoChan
+ if eventInfo.Error != nil || eventInfo.Event != expectedEvents[0] {
+ t.Fatalf("got:\n%#v\nexpected:\n%#v", eventInfo, expectedEvents[0])
+ }
+ close(stopChan)
+ for i := 0; i < 3; i++ {
+ _, ok := <-eventInfoChan
+ if i == 2 && ok {
+ t.Fatalf("read more than 2 events successfully after closing stopChan")
+ }
+ }
+
+ // test when you don't pass stop chan
+ eventInfoChan, err = client.MonitorEvents(nil, nil)
+ if err != nil {
+ t.Fatalf("cannot get events from server: %s", err.Error())
+ }
+
+ for i, expectedEvent := range expectedEvents {
+ t.Logf("on iter %d\n", i)
+ eventInfo := <-eventInfoChan
+ if eventInfo.Error != nil || eventInfo.Event != expectedEvent {
+ t.Fatalf("index %d, got:\n%#v\nexpected:\n%#v", i, eventInfo, expectedEvent)
+ }
+ t.Logf("done with iter %d\n", i)
+ }
+}
+
+func TestDockerClientInterface(t *testing.T) {
+ iface := reflect.TypeOf((*Client)(nil)).Elem()
+ test := testDockerClient(t)
+
+ if !reflect.TypeOf(test).Implements(iface) {
+ t.Fatalf("DockerClient does not implement the Client interface")
+ }
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/engine_mock_test.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/engine_mock_test.go
new file mode 100644
index 00000000..b2382a15
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/engine_mock_test.go
@@ -0,0 +1,254 @@
+package dockerclient
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "net/http/httptest"
+ "strconv"
+ "time"
+
+ "github.com/docker/docker/pkg/ioutils"
+ "github.com/docker/docker/pkg/jsonlog"
+ "github.com/docker/docker/pkg/stdcopy"
+ "github.com/gorilla/mux"
+)
+
+var (
+ testHTTPServer *httptest.Server
+)
+
+func init() {
+ r := mux.NewRouter()
+ baseURL := "/" + APIVersion
+ r.HandleFunc(baseURL+"/info", handlerGetInfo).Methods("GET")
+ r.HandleFunc(baseURL+"/containers/json", handlerGetContainers).Methods("GET")
+ r.HandleFunc(baseURL+"/containers/{id}/logs", handleContainerLogs).Methods("GET")
+ r.HandleFunc(baseURL+"/containers/{id}/changes", handleContainerChanges).Methods("GET")
+ r.HandleFunc(baseURL+"/containers/{id}/stats", handleContainerStats).Methods("GET")
+ r.HandleFunc(baseURL+"/containers/{id}/kill", handleContainerKill).Methods("POST")
+ r.HandleFunc(baseURL+"/containers/{id}/wait", handleWait).Methods("POST")
+ r.HandleFunc(baseURL+"/images/create", handleImagePull).Methods("POST")
+ r.HandleFunc(baseURL+"/events", handleEvents).Methods("GET")
+ testHTTPServer = httptest.NewServer(handlerAccessLog(r))
+}
+
+func handlerAccessLog(handler http.Handler) http.Handler {
+ logHandler := func(w http.ResponseWriter, r *http.Request) {
+ log.Printf("%s \"%s %s\"", r.RemoteAddr, r.Method, r.URL)
+ handler.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(logHandler)
+}
+
+func handleContainerKill(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "{%q:%q", "Id", "421373210afd132")
+}
+
+func handleWait(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ if vars["id"] == "valid-id" {
+ fmt.Fprintf(w, `{"StatusCode":0}`)
+ } else {
+ http.Error(w, "failed", 500)
+ }
+}
+
+func handleImagePull(w http.ResponseWriter, r *http.Request) {
+ imageName := r.URL.Query()["fromImage"][0]
+ responses := []map[string]interface{}{{
+ "status": fmt.Sprintf("Pulling repository mydockerregistry/%s", imageName),
+ }}
+ switch imageName {
+ case "busybox":
+ responses = append(responses, map[string]interface{}{
+ "status": "Status: Image is up to date for mydockerregistry/busybox",
+ })
+ case "haproxy":
+ fmt.Fprintf(w, haproxyPullOutput)
+ return
+ default:
+ errorMsg := fmt.Sprintf("Error: image %s not found", imageName)
+ responses = append(responses, map[string]interface{}{
+ "errorDetail": map[string]interface{}{
+ "message": errorMsg,
+ },
+ "error": errorMsg,
+ })
+ }
+ for _, response := range responses {
+ json.NewEncoder(w).Encode(response)
+ }
+}
+
+func handleContainerLogs(w http.ResponseWriter, r *http.Request) {
+ var outStream, errStream io.Writer
+ outStream = ioutils.NewWriteFlusher(w)
+
+ // not sure how to test follow
+ if err := r.ParseForm(); err != nil {
+ http.Error(w, err.Error(), 500)
+ }
+ stdout, stderr := getBoolValue(r.Form.Get("stdout")), getBoolValue(r.Form.Get("stderr"))
+ if stderr {
+ errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
+ }
+ if stdout {
+ outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
+ }
+ var i int
+ if tail, err := strconv.Atoi(r.Form.Get("tail")); err == nil && tail > 0 {
+ i = 50 - tail
+ if i < 0 {
+ i = 0
+ }
+ }
+ for ; i < 50; i++ {
+ line := fmt.Sprintf("line %d", i)
+ if getBoolValue(r.Form.Get("timestamps")) {
+ l := &jsonlog.JSONLog{Log: line, Created: time.Now().UTC()}
+ line = fmt.Sprintf("%s %s", l.Created.Format(jsonlog.RFC3339NanoFixed), line)
+ }
+ if i%2 == 0 && stderr {
+ fmt.Fprintln(errStream, line)
+ } else if i%2 == 1 && stdout {
+ fmt.Fprintln(outStream, line)
+ }
+ }
+}
+
+func handleContainerChanges(w http.ResponseWriter, r *http.Request) {
+ writeHeaders(w, 200, "changes")
+ body := `[
+ {
+ "Path": "/dev",
+ "Kind": 0
+ },
+ {
+ "Path": "/dev/kmsg",
+ "Kind": 1
+ },
+ {
+ "Path": "/test",
+ "Kind": 1
+ }
+ ]`
+ w.Write([]byte(body))
+}
+
+func handleContainerStats(w http.ResponseWriter, r *http.Request) {
+ switch mux.Vars(r)["id"] {
+ case "foobar":
+ fmt.Fprintf(w, "%s invalidresp", statsResp)
+ default:
+ fmt.Fprintf(w, "%s %s", statsResp, statsResp)
+ }
+}
+
+func getBoolValue(boolString string) bool {
+ switch boolString {
+ case "1":
+ return true
+ case "True":
+ return true
+ case "true":
+ return true
+ default:
+ return false
+ }
+}
+
+func writeHeaders(w http.ResponseWriter, code int, jobName string) {
+ h := w.Header()
+ h.Add("Content-Type", "application/json")
+ if jobName != "" {
+ h.Add("Job-Name", jobName)
+ }
+ w.WriteHeader(code)
+}
+
+func handlerGetInfo(w http.ResponseWriter, r *http.Request) {
+ writeHeaders(w, 200, "info")
+ body := `{
+ "Containers": 2,
+ "Debug": 1,
+ "Driver": "aufs",
+ "DriverStatus": [["Root Dir", "/mnt/sda1/var/lib/docker/aufs"],
+ ["Dirs", "0"]],
+ "ExecutionDriver": "native-0.2",
+ "IPv4Forwarding": 1,
+ "Images": 1,
+ "IndexServerAddress": "https://index.docker.io/v1/",
+ "InitPath": "/usr/local/bin/docker",
+ "InitSha1": "",
+ "KernelVersion": "3.16.4-tinycore64",
+ "MemoryLimit": 1,
+ "NEventsListener": 0,
+ "NFd": 10,
+ "NGoroutines": 11,
+ "OperatingSystem": "Boot2Docker 1.3.1 (TCL 5.4); master : a083df4 - Thu Jan 01 00:00:00 UTC 1970",
+ "SwapLimit": 1}`
+ w.Write([]byte(body))
+}
+
+func handlerGetContainers(w http.ResponseWriter, r *http.Request) {
+ writeHeaders(w, 200, "containers")
+ body := `[
+ {
+ "Status": "Up 39 seconds",
+ "Ports": [
+ {
+ "Type": "tcp",
+ "PublicPort": 49163,
+ "PrivatePort": 8080,
+ "IP": "0.0.0.0"
+ }
+ ],
+ "Names": [
+ "/trusting_heisenberg"
+ ],
+ "Image": "foo:latest",
+ "Id": "332375cfbc23edb921a21026314c3497674ba8bdcb2c85e0e65ebf2017f688ce",
+ "Created": 1415720105,
+ "Command": "/bin/go-run"
+ }
+ ]`
+ if v, ok := r.URL.Query()["size"]; ok {
+ if v[0] == "1" {
+ body = `[
+ {
+ "Status": "Up 39 seconds",
+ "Ports": [
+ {
+ "Type": "tcp",
+ "PublicPort": 49163,
+ "PrivatePort": 8080,
+ "IP": "0.0.0.0"
+ }
+ ],
+ "Names": [
+ "/trusting_heisenberg"
+ ],
+ "Image": "foo:latest",
+ "Id": "332375cfbc23edb921a21026314c3497674ba8bdcb2c85e0e65ebf2017f688ce",
+ "Created": 1415720105,
+ "SizeRootFs": 12345,
+ "SizeRW": 123,
+ "Command": "/bin/go-run"
+ }
+ ]`
+ }
+ }
+ if v, ok := r.URL.Query()["filters"]; ok {
+ if v[0] != "{'id':['332375cfbc23edb921a21026314c3497674ba8bdcb2c85e0e65ebf2017f688ce']}" {
+ body = "[]"
+ }
+ }
+ w.Write([]byte(body))
+}
+
+func handleEvents(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte(eventsResp))
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/example_responses.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/example_responses.go
new file mode 100644
index 00000000..e4c890dc
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/example_responses.go
@@ -0,0 +1,15 @@
+package dockerclient
+
+var haproxyPullOutput = `{"status":"The image you are pulling has been verified","id":"haproxy:1"}
+{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"ecb4b23ca7ce"}{"status":"Already exists","progressDetail":{},"id":"f453e940c177"}{"status":"Already exists","progressDetail":{},"id":"fc5ea1bc05ab"}{"status":"Already exists","progressDetail":{},"id":"380557f8f7b3"}{"status":"The image you are pulling has been verified","id":"haproxy:1.4"}
+{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"63a1b9929e14"}{"status":"Already exists","progressDetail":{},"id":"af43bf7d176e"}{"status":"Already exists","progressDetail":{},"id":"851aac2d69aa"}{"status":"Already exists","progressDetail":{},"id":"345053a92c95"}{"status":"Already exists","progressDetail":{},"id":"b41231d429c9"}{"status":"The image you are pulling has been verified","id":"haproxy:1.4.25"}
+{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"63a1b9929e14"}{"status":"Already exists","progressDetail":{},"id":"af43bf7d176e"}{"status":"Already exists","progressDetail":{},"id":"851aac2d69aa"}{"status":"Already exists","progressDetail":{},"id":"345053a92c95"}{"status":"Already exists","progressDetail":{},"id":"b41231d429c9"}{"status":"The image you are pulling has been verified","id":"haproxy:1.5"}
+{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"ecb4b23ca7ce"}{"status":"Already exists","progressDetail":{},"id":"f453e940c177"}{"status":"Already exists","progressDetail":{},"id":"fc5ea1bc05ab"}{"status":"Already exists","progressDetail":{},"id":"380557f8f7b3"}{"status":"The image you are pulling has been verified","id":"haproxy:1.5.10"}
+{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"ecb4b23ca7ce"}{"status":"Already exists","progressDetail":{},"id":"f453e940c177"}{"status":"Already exists","progressDetail":{},"id":"fc5ea1bc05ab"}{"status":"Already exists","progressDetail":{},"id":"380557f8f7b3"}{"status":"The image you are pulling has been verified","id":"haproxy:1.5.9"}
+{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"3d894e6f7e63"}{"status":"Already exists","progressDetail":{},"id":"4d949c40bc77"}{"status":"Already exists","progressDetail":{},"id":"55e031889365"}{"status":"Already exists","progressDetail":{},"id":"c7aa675e1876"}{"status":"The image you are pulling has been verified","id":"haproxy:latest"}
+{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"ecb4b23ca7ce"}{"status":"Already exists","progressDetail":{},"id":"f453e940c177"}{"status":"Already exists","progressDetail":{},"id":"fc5ea1bc05ab"}{"status":"Already exists","progressDetail":{},"id":"380557f8f7b3"}{"status":"Status: Image is up to date for haproxy"}
+`
+
+var statsResp = `{"read":"2015-02-02T17:06:08.187833376-05:00","network":{"rx_bytes":99988,"rx_packets":928,"rx_errors":0,"rx_dropped":0,"tx_bytes":1786548,"tx_packets":877,"tx_errors":0,"tx_dropped":0},"cpu_stats":{"cpu_usage":{"total_usage":170018598,"percpu_usage":[170018598],"usage_in_kernelmode":30000000,"usage_in_usermode":70000000},"system_cpu_usage":9020930000000,"throttling_data":{"periods":0,"throttled_periods":0,"throttled_time":0}},"memory_stats":{"usage":18022400,"max_usage":20541440,"stats":{"active_anon":6213632,"active_file":176128,"cache":11808768,"hierarchical_memory_limit":9223372036854775807,"hierarchical_memsw_limit":9223372036854775807,"inactive_anon":0,"inactive_file":11632640,"mapped_file":5165056,"pgfault":2535,"pgmajfault":13,"pgpgin":4293,"pgpgout":1937,"rss":6213632,"rss_huge":2097152,"swap":0,"total_active_anon":6213632,"total_active_file":176128,"total_cache":11808768,"total_inactive_anon":0,"total_inactive_file":11632640,"total_mapped_file":5165056,"total_pgfault":2535,"total_pgmajfault":13,"total_pgpgin":4293,"total_pgpgout":1937,"total_rss":6213632,"total_rss_huge":2097152,"total_swap":0,"total_unevictable":0,"unevictable":0},"failcnt":0,"limit":1041051648},"blkio_stats":{"io_service_bytes_recursive":[{"major":7,"minor":0,"op":"Read","value":28672},{"major":7,"minor":0,"op":"Write","value":0},{"major":7,"minor":0,"op":"Sync","value":0},{"major":7,"minor":0,"op":"Async","value":28672},{"major":7,"minor":0,"op":"Total","value":28672},{"major":253,"minor":0,"op":"Read","value":28672},{"major":253,"minor":0,"op":"Write","value":0},{"major":253,"minor":0,"op":"Sync","value":0},{"major":253,"minor":0,"op":"Async","value":28672},{"major":253,"minor":0,"op":"Total","value":28672},{"major":253,"minor":7,"op":"Read","value":11718656},{"major":253,"minor":7,"op":"Write","value":0},{"major":253,"minor":7,"op":"Sync","value":0},{"major":253,"minor":7,"op":"Async","value":11718656},{"major":253,"minor":7,"op":"Total","value":11718656},{"major":202,"minor":0,"op":"Read","value":0},{"major":202,"minor":0,"op":"Write","value":0},{"major":202,"minor":0,"op":"Sync","value":0},{"major":202,"minor":0,"op":"Async","value":0},{"major":202,"minor":0,"op":"Total","value":0}],"io_serviced_recursive":[{"major":7,"minor":0,"op":"Read","value":7},{"major":7,"minor":0,"op":"Write","value":0},{"major":7,"minor":0,"op":"Sync","value":0},{"major":7,"minor":0,"op":"Async","value":7},{"major":7,"minor":0,"op":"Total","value":7},{"major":253,"minor":0,"op":"Read","value":7},{"major":253,"minor":0,"op":"Write","value":0},{"major":253,"minor":0,"op":"Sync","value":0},{"major":253,"minor":0,"op":"Async","value":7},{"major":253,"minor":0,"op":"Total","value":7},{"major":253,"minor":7,"op":"Read","value":312},{"major":253,"minor":7,"op":"Write","value":0},{"major":253,"minor":7,"op":"Sync","value":0},{"major":253,"minor":7,"op":"Async","value":312},{"major":253,"minor":7,"op":"Total","value":312},{"major":202,"minor":0,"op":"Read","value":0},{"major":202,"minor":0,"op":"Write","value":0},{"major":202,"minor":0,"op":"Sync","value":0},{"major":202,"minor":0,"op":"Async","value":0},{"major":202,"minor":0,"op":"Total","value":0}],"io_queue_recursive":[],"io_service_time_recursive":[],"io_wait_time_recursive":[],"io_merged_recursive":[],"io_time_recursive":[],"sectors_recursive":[]}}`
+
+var eventsResp = `{"status":"pull","id":"nginx:latest","time":1428620433}{"status":"create","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620433}{"status":"start","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620433}{"status":"die","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620442}{"status":"create","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"start","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"die","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"pull","id":"debian:latest","time":1428620453}{"status":"create","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"start","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"die","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"create","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620458}{"status":"start","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620458}{"status":"pause","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620462}{"status":"unpause","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620466}{"status":"die","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620469}`
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/examples/events.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/examples/events.go
new file mode 100644
index 00000000..2d6de40c
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/examples/events.go
@@ -0,0 +1,39 @@
+package main
+
+import (
+ "github.com/samalba/dockerclient"
+ "log"
+ "os"
+ "os/signal"
+ "syscall"
+)
+
+func eventCallback(e *dockerclient.Event, ec chan error, args ...interface{}) {
+ log.Println(e)
+}
+
+var (
+ client *dockerclient.DockerClient
+)
+
+func waitForInterrupt() {
+ sigChan := make(chan os.Signal, 1)
+ signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
+ for _ = range sigChan {
+ client.StopAllMonitorEvents()
+ os.Exit(0)
+ }
+}
+
+func main() {
+ docker, err := dockerclient.NewDockerClient(os.Getenv("DOCKER_HOST"), nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ client = docker
+
+ client.StartMonitorEvents(eventCallback, nil)
+
+ waitForInterrupt()
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/examples/stats/stats.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/examples/stats/stats.go
new file mode 100644
index 00000000..81ee2fb4
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/examples/stats/stats.go
@@ -0,0 +1,43 @@
+package main
+
+import (
+ "github.com/samalba/dockerclient"
+ "log"
+ "os"
+ "os/signal"
+ "syscall"
+)
+
+func statCallback(id string, stat *dockerclient.Stats, ec chan error, args ...interface{}) {
+ log.Println(stat)
+}
+
+func waitForInterrupt() {
+ sigChan := make(chan os.Signal, 1)
+ signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
+ for _ = range sigChan {
+ os.Exit(0)
+ }
+}
+
+func main() {
+ docker, err := dockerclient.NewDockerClient(os.Getenv("DOCKER_HOST"), nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ containerConfig := &dockerclient.ContainerConfig{Image: "busybox", Cmd: []string{"sh"}}
+ containerId, err := docker.CreateContainer(containerConfig, "", nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Start the container
+ err = docker.StartContainer(containerId, nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+ docker.StartMonitorStats(containerId, statCallback, nil)
+
+ waitForInterrupt()
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/interface.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/interface.go
new file mode 100644
index 00000000..b373055e
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/interface.go
@@ -0,0 +1,66 @@
+package dockerclient
+
+import (
+ "io"
+)
+
+type Callback func(*Event, chan error, ...interface{})
+
+type StatCallback func(string, *Stats, chan error, ...interface{})
+
+type Client interface {
+ Info() (*Info, error)
+ ListContainers(all, size bool, filters string) ([]Container, error)
+ InspectContainer(id string) (*ContainerInfo, error)
+ InspectImage(id string) (*ImageInfo, error)
+ CreateContainer(config *ContainerConfig, name string, authConfig *AuthConfig) (string, error)
+ ContainerLogs(id string, options *LogOptions) (io.ReadCloser, error)
+ ContainerChanges(id string) ([]*ContainerChanges, error)
+ // ContainerStats takes a container ID and an optional stop channel and
+ // returns a StatsOrError channel. If an error is ever sent, then no
+ // more stats will be sent on that channel. If a stop channel is
+ // provided, events will stop being monitored after the stop channel is
+ // closed.
+ ContainerStats(id string, stopChan <-chan struct{}) (<-chan StatsOrError, error)
+ ExecCreate(config *ExecConfig) (string, error)
+ ExecStart(id string, config *ExecConfig) error
+ ExecResize(id string, width, height int) error
+ StartContainer(id string, config *HostConfig) error
+ AttachContainer(id string, options *AttachOptions) (io.ReadCloser, error)
+ StopContainer(id string, timeout int) error
+ RestartContainer(id string, timeout int) error
+ KillContainer(id, signal string) error
+ Wait(id string) <-chan WaitResult
+ // MonitorEvents takes options and an optional stop channel, and returns
+ // an EventOrError channel. If an error is ever sent, then no more
+ // events will be sent. If a stop channel is provided, events will stop
+ // being monitored after the stop channel is closed.
+ MonitorEvents(options *MonitorEventsOptions, stopChan <-chan struct{}) (<-chan EventOrError, error)
+ StartMonitorEvents(cb Callback, ec chan error, args ...interface{})
+ StopAllMonitorEvents()
+ StartMonitorStats(id string, cb StatCallback, ec chan error, args ...interface{})
+ StopAllMonitorStats()
+ TagImage(nameOrID string, repo string, tag string, force bool) error
+ Version() (*Version, error)
+ PullImage(name string, auth *AuthConfig) error
+ PushImage(name string, tag string, auth *AuthConfig) error
+ LoadImage(reader io.Reader) error
+ RemoveContainer(id string, force, volumes bool) error
+ ListImages(all bool) ([]*Image, error)
+ RemoveImage(name string, force bool) ([]*ImageDelete, error)
+ SearchImages(query, registry string, auth *AuthConfig) ([]ImageSearch, error)
+ PauseContainer(name string) error
+ UnpauseContainer(name string) error
+ RenameContainer(oldName string, newName string) error
+ ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error)
+ BuildImage(image *BuildImage) (io.ReadCloser, error)
+ ListVolumes() ([]*Volume, error)
+ RemoveVolume(name string) error
+ CreateVolume(request *VolumeCreateRequest) (*Volume, error)
+ ListNetworks(filters string) ([]*NetworkResource, error)
+ InspectNetwork(id string) (*NetworkResource, error)
+ CreateNetwork(config *NetworkCreate) (*NetworkCreateResponse, error)
+ ConnectNetwork(id, container string) error
+ DisconnectNetwork(id, container string, force bool) error
+ RemoveNetwork(id string) error
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/mockclient/mock.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/mockclient/mock.go
new file mode 100644
index 00000000..9da36b87
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/mockclient/mock.go
@@ -0,0 +1,237 @@
+package mockclient
+
+import (
+ "io"
+
+ "github.com/samalba/dockerclient"
+ "github.com/stretchr/testify/mock"
+)
+
+type MockClient struct {
+ mock.Mock
+}
+
+func NewMockClient() *MockClient {
+ return &MockClient{}
+}
+
+func (client *MockClient) Info() (*dockerclient.Info, error) {
+ args := client.Mock.Called()
+ return args.Get(0).(*dockerclient.Info), args.Error(1)
+}
+
+func (client *MockClient) ListContainers(all bool, size bool, filters string) ([]dockerclient.Container, error) {
+ args := client.Mock.Called(all, size, filters)
+ return args.Get(0).([]dockerclient.Container), args.Error(1)
+}
+
+func (client *MockClient) InspectContainer(id string) (*dockerclient.ContainerInfo, error) {
+ args := client.Mock.Called(id)
+ return args.Get(0).(*dockerclient.ContainerInfo), args.Error(1)
+}
+
+func (client *MockClient) InspectImage(id string) (*dockerclient.ImageInfo, error) {
+ args := client.Mock.Called(id)
+ return args.Get(0).(*dockerclient.ImageInfo), args.Error(1)
+}
+
+func (client *MockClient) CreateContainer(config *dockerclient.ContainerConfig, name string, authConfig *dockerclient.AuthConfig) (string, error) {
+ args := client.Mock.Called(config, name, authConfig)
+ return args.String(0), args.Error(1)
+}
+
+func (client *MockClient) ContainerLogs(id string, options *dockerclient.LogOptions) (io.ReadCloser, error) {
+ args := client.Mock.Called(id, options)
+ return args.Get(0).(io.ReadCloser), args.Error(1)
+}
+
+func (client *MockClient) ContainerChanges(id string) ([]*dockerclient.ContainerChanges, error) {
+ args := client.Mock.Called(id)
+ return args.Get(0).([]*dockerclient.ContainerChanges), args.Error(1)
+}
+
+func (client *MockClient) ContainerStats(id string, stopChan <-chan struct{}) (<-chan dockerclient.StatsOrError, error) {
+ args := client.Mock.Called(id, stopChan)
+ return args.Get(0).(<-chan dockerclient.StatsOrError), args.Error(1)
+}
+
+func (client *MockClient) AttachContainer(id string, options *dockerclient.AttachOptions) (io.ReadCloser, error) {
+ args := client.Mock.Called(id, options)
+ return args.Get(0).(io.ReadCloser), args.Error(1)
+}
+
+func (client *MockClient) StartContainer(id string, config *dockerclient.HostConfig) error {
+ args := client.Mock.Called(id, config)
+ return args.Error(0)
+}
+
+func (client *MockClient) StopContainer(id string, timeout int) error {
+ args := client.Mock.Called(id, timeout)
+ return args.Error(0)
+}
+
+func (client *MockClient) RestartContainer(id string, timeout int) error {
+ args := client.Mock.Called(id, timeout)
+ return args.Error(0)
+}
+
+func (client *MockClient) KillContainer(id, signal string) error {
+ args := client.Mock.Called(id, signal)
+ return args.Error(0)
+}
+
+func (client *MockClient) Wait(id string) <-chan dockerclient.WaitResult {
+ args := client.Mock.Called(id)
+ return args.Get(0).(<-chan dockerclient.WaitResult)
+}
+
+func (client *MockClient) MonitorEvents(options *dockerclient.MonitorEventsOptions, stopChan <-chan struct{}) (<-chan dockerclient.EventOrError, error) {
+ args := client.Mock.Called(options, stopChan)
+ return args.Get(0).(<-chan dockerclient.EventOrError), args.Error(1)
+}
+
+func (client *MockClient) StartMonitorEvents(cb dockerclient.Callback, ec chan error, args ...interface{}) {
+ client.Mock.Called(cb, ec, args)
+}
+
+func (client *MockClient) StopAllMonitorEvents() {
+ client.Mock.Called()
+}
+
+func (client *MockClient) TagImage(nameOrID string, repo string, tag string, force bool) error {
+ args := client.Mock.Called(nameOrID, repo, tag, force)
+ return args.Error(0)
+}
+
+func (client *MockClient) StartMonitorStats(id string, cb dockerclient.StatCallback, ec chan error, args ...interface{}) {
+ client.Mock.Called(id, cb, ec, args)
+}
+
+func (client *MockClient) StopAllMonitorStats() {
+ client.Mock.Called()
+}
+
+func (client *MockClient) Version() (*dockerclient.Version, error) {
+ args := client.Mock.Called()
+ return args.Get(0).(*dockerclient.Version), args.Error(1)
+}
+
+func (client *MockClient) PullImage(name string, auth *dockerclient.AuthConfig) error {
+ args := client.Mock.Called(name, auth)
+ return args.Error(0)
+}
+
+func (client *MockClient) PushImage(name string, tag string, auth *dockerclient.AuthConfig) error {
+ args := client.Mock.Called(name, tag, auth)
+ return args.Error(0)
+}
+
+func (client *MockClient) LoadImage(reader io.Reader) error {
+ args := client.Mock.Called(reader)
+ return args.Error(0)
+}
+
+func (client *MockClient) RemoveContainer(id string, force, volumes bool) error {
+ args := client.Mock.Called(id, force, volumes)
+ return args.Error(0)
+}
+
+func (client *MockClient) ListImages(all bool) ([]*dockerclient.Image, error) {
+ args := client.Mock.Called(all)
+ return args.Get(0).([]*dockerclient.Image), args.Error(1)
+}
+
+func (client *MockClient) RemoveImage(name string, force bool) ([]*dockerclient.ImageDelete, error) {
+ args := client.Mock.Called(name, force)
+ return args.Get(0).([]*dockerclient.ImageDelete), args.Error(1)
+}
+
+func (client *MockClient) SearchImages(query, registry string, authConfig *dockerclient.AuthConfig) ([]dockerclient.ImageSearch, error) {
+ args := client.Mock.Called(query, registry, authConfig)
+ return args.Get(0).([]dockerclient.ImageSearch), args.Error(1)
+}
+
+func (client *MockClient) PauseContainer(name string) error {
+ args := client.Mock.Called(name)
+ return args.Error(0)
+}
+
+func (client *MockClient) UnpauseContainer(name string) error {
+ args := client.Mock.Called(name)
+ return args.Error(0)
+}
+
+func (client *MockClient) ExecCreate(config *dockerclient.ExecConfig) (string, error) {
+ args := client.Mock.Called(config)
+ return args.String(0), args.Error(1)
+}
+
+func (client *MockClient) ExecStart(id string, config *dockerclient.ExecConfig) error {
+ args := client.Mock.Called(id, config)
+ return args.Error(0)
+}
+
+func (client *MockClient) ExecResize(id string, width, height int) error {
+ args := client.Mock.Called(id, width, height)
+ return args.Error(0)
+}
+
+func (client *MockClient) RenameContainer(oldName string, newName string) error {
+ args := client.Mock.Called(oldName, newName)
+ return args.Error(0)
+}
+
+func (client *MockClient) ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error) {
+ args := client.Mock.Called(source, repository, tag, tar)
+ return args.Get(0).(io.ReadCloser), args.Error(1)
+}
+
+func (client *MockClient) BuildImage(image *dockerclient.BuildImage) (io.ReadCloser, error) {
+ args := client.Mock.Called(image)
+ return args.Get(0).(io.ReadCloser), args.Error(1)
+}
+
+func (client *MockClient) ListVolumes() ([]*dockerclient.Volume, error) {
+ args := client.Mock.Called()
+ return args.Get(0).([]*dockerclient.Volume), args.Error(1)
+}
+
+func (client *MockClient) RemoveVolume(name string) error {
+ args := client.Mock.Called(name)
+ return args.Error(0)
+}
+
+func (client *MockClient) CreateVolume(request *dockerclient.VolumeCreateRequest) (*dockerclient.Volume, error) {
+ args := client.Mock.Called(request)
+ return args.Get(0).(*dockerclient.Volume), args.Error(1)
+}
+
+func (client *MockClient) ListNetworks(filters string) ([]*dockerclient.NetworkResource, error) {
+ args := client.Mock.Called(filters)
+ return args.Get(0).([]*dockerclient.NetworkResource), args.Error(1)
+}
+
+func (client *MockClient) InspectNetwork(id string) (*dockerclient.NetworkResource, error) {
+ args := client.Mock.Called(id)
+ return args.Get(0).(*dockerclient.NetworkResource), args.Error(1)
+}
+
+func (client *MockClient) CreateNetwork(config *dockerclient.NetworkCreate) (*dockerclient.NetworkCreateResponse, error) {
+ args := client.Mock.Called(config)
+ return args.Get(0).(*dockerclient.NetworkCreateResponse), args.Error(1)
+}
+
+func (client *MockClient) ConnectNetwork(id, container string) error {
+ args := client.Mock.Called(id, container)
+ return args.Error(0)
+}
+
+func (client *MockClient) DisconnectNetwork(id, container string, force bool) error {
+ args := client.Mock.Called(id, container, force)
+ return args.Error(0)
+}
+
+func (client *MockClient) RemoveNetwork(id string) error {
+ args := client.Mock.Called(id)
+ return args.Error(0)
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/mockclient/mock_test.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/mockclient/mock_test.go
new file mode 100644
index 00000000..8d91bcf6
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/mockclient/mock_test.go
@@ -0,0 +1,32 @@
+package mockclient
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/samalba/dockerclient"
+)
+
+func TestMock(t *testing.T) {
+ mock := NewMockClient()
+ mock.On("Version").Return(&dockerclient.Version{Version: "foo"}, nil).Once()
+
+ v, err := mock.Version()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if v.Version != "foo" {
+ t.Fatal(v)
+ }
+
+ mock.Mock.AssertExpectations(t)
+}
+
+func TestMockInterface(t *testing.T) {
+ iface := reflect.TypeOf((*dockerclient.Client)(nil)).Elem()
+ mock := NewMockClient()
+
+ if !reflect.TypeOf(mock).Implements(iface) {
+ t.Fatalf("Mock does not implement the Client interface")
+ }
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/nopclient/nop.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/nopclient/nop.go
new file mode 100644
index 00000000..659b57b7
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/nopclient/nop.go
@@ -0,0 +1,199 @@
+package nopclient
+
+import (
+ "errors"
+ "io"
+
+ "github.com/samalba/dockerclient"
+)
+
+var (
+ ErrNoEngine = errors.New("Engine no longer exists")
+)
+
+type NopClient struct {
+}
+
+func NewNopClient() *NopClient {
+ return &NopClient{}
+}
+
+func (client *NopClient) Info() (*dockerclient.Info, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) ListContainers(all bool, size bool, filters string) ([]dockerclient.Container, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) InspectContainer(id string) (*dockerclient.ContainerInfo, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) InspectImage(id string) (*dockerclient.ImageInfo, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) CreateContainer(config *dockerclient.ContainerConfig, name string, authConfig *dockerclient.AuthConfig) (string, error) {
+ return "", ErrNoEngine
+}
+
+func (client *NopClient) ContainerLogs(id string, options *dockerclient.LogOptions) (io.ReadCloser, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) ContainerChanges(id string) ([]*dockerclient.ContainerChanges, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) ContainerStats(id string, stopChan <-chan struct{}) (<-chan dockerclient.StatsOrError, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) AttachContainer(id string, options *dockerclient.AttachOptions) (io.ReadCloser, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) StartContainer(id string, config *dockerclient.HostConfig) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) StopContainer(id string, timeout int) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) RestartContainer(id string, timeout int) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) KillContainer(id, signal string) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) Wait(id string) <-chan dockerclient.WaitResult {
+ return nil
+}
+
+func (client *NopClient) MonitorEvents(options *dockerclient.MonitorEventsOptions, stopChan <-chan struct{}) (<-chan dockerclient.EventOrError, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) StartMonitorEvents(cb dockerclient.Callback, ec chan error, args ...interface{}) {
+ return
+}
+
+func (client *NopClient) StopAllMonitorEvents() {
+ return
+}
+
+func (client *NopClient) TagImage(nameOrID string, repo string, tag string, force bool) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) StartMonitorStats(id string, cb dockerclient.StatCallback, ec chan error, args ...interface{}) {
+ return
+}
+
+func (client *NopClient) StopAllMonitorStats() {
+ return
+}
+
+func (client *NopClient) Version() (*dockerclient.Version, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) PullImage(name string, auth *dockerclient.AuthConfig) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) PushImage(name, tag string, auth *dockerclient.AuthConfig) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) LoadImage(reader io.Reader) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) RemoveContainer(id string, force, volumes bool) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) ListImages(all bool) ([]*dockerclient.Image, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) RemoveImage(name string, force bool) ([]*dockerclient.ImageDelete, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) SearchImages(query, registry string, authConfig *dockerclient.AuthConfig) ([]dockerclient.ImageSearch, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) PauseContainer(name string) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) UnpauseContainer(name string) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) ExecCreate(config *dockerclient.ExecConfig) (string, error) {
+ return "", ErrNoEngine
+}
+
+func (client *NopClient) ExecStart(id string, config *dockerclient.ExecConfig) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) ExecResize(id string, width, height int) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) RenameContainer(oldName string, newName string) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) BuildImage(image *dockerclient.BuildImage) (io.ReadCloser, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) ListVolumes() ([]*dockerclient.Volume, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) RemoveVolume(name string) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) CreateVolume(request *dockerclient.VolumeCreateRequest) (*dockerclient.Volume, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) ListNetworks(filters string) ([]*dockerclient.NetworkResource, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) InspectNetwork(id string) (*dockerclient.NetworkResource, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) CreateNetwork(config *dockerclient.NetworkCreate) (*dockerclient.NetworkCreateResponse, error) {
+ return nil, ErrNoEngine
+}
+
+func (client *NopClient) ConnectNetwork(id, container string) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) DisconnectNetwork(id, container string, force bool) error {
+ return ErrNoEngine
+}
+
+func (client *NopClient) RemoveNetwork(id string) error {
+ return ErrNoEngine
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/tls.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/tls.go
new file mode 100644
index 00000000..80ae6f1e
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/tls.go
@@ -0,0 +1,38 @@
+package dockerclient
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "errors"
+ "io/ioutil"
+ "path/filepath"
+)
+
+// TLSConfigFromCertPath returns a configuration based on PEM files in the directory
+//
+// path is usually what is set by the environment variable `DOCKER_CERT_PATH`,
+// or `$HOME/.docker`.
+func TLSConfigFromCertPath(path string) (*tls.Config, error) {
+ cert, err := ioutil.ReadFile(filepath.Join(path, "cert.pem"))
+ if err != nil {
+ return nil, err
+ }
+ key, err := ioutil.ReadFile(filepath.Join(path, "key.pem"))
+ if err != nil {
+ return nil, err
+ }
+ ca, err := ioutil.ReadFile(filepath.Join(path, "ca.pem"))
+ if err != nil {
+ return nil, err
+ }
+ tlsCert, err := tls.X509KeyPair(cert, key)
+ if err != nil {
+ return nil, err
+ }
+ tlsConfig := &tls.Config{Certificates: []tls.Certificate{tlsCert}}
+ tlsConfig.RootCAs = x509.NewCertPool()
+ if !tlsConfig.RootCAs.AppendCertsFromPEM(ca) {
+ return nil, errors.New("Could not add RootCA pem")
+ }
+ return tlsConfig, nil
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/types.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/types.go
new file mode 100644
index 00000000..7ba79915
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/types.go
@@ -0,0 +1,624 @@
+package dockerclient
+
+import (
+ "fmt"
+ "io"
+ "time"
+
+ "github.com/docker/go-units"
+)
+
+type ContainerConfig struct {
+ Hostname string
+ Domainname string
+ User string
+ AttachStdin bool
+ AttachStdout bool
+ AttachStderr bool
+ ExposedPorts map[string]struct{}
+ Tty bool
+ OpenStdin bool
+ StdinOnce bool
+ Env []string
+ Cmd []string
+ Image string
+ Volumes map[string]struct{}
+ WorkingDir string
+ Entrypoint []string
+ NetworkDisabled bool
+ MacAddress string
+ OnBuild []string
+ Labels map[string]string
+ StopSignal string
+
+ // FIXME: VolumeDriver have been removed since docker 1.9
+ VolumeDriver string
+
+ // FIXME: The following fields have been removed since API v1.18
+ Memory int64
+ MemorySwap int64
+ CpuShares int64
+ Cpuset string
+ PortSpecs []string
+
+ // This is used only by the create command
+ HostConfig HostConfig
+
+ // Network configuration support
+ NetworkingConfig NetworkingConfig
+}
+
+type HostConfig struct {
+ Binds []string
+ ContainerIDFile string
+ LxcConf []map[string]string
+ Memory int64
+ MemoryReservation int64
+ MemorySwap int64
+ KernelMemory int64
+ CpuShares int64
+ CpuPeriod int64
+ CpusetCpus string
+ CpusetMems string
+ CpuQuota int64
+ BlkioWeight int64
+ OomKillDisable bool
+ MemorySwappiness int64
+ Privileged bool
+ PortBindings map[string][]PortBinding
+ Links []string
+ PublishAllPorts bool
+ Dns []string
+ DNSOptions []string
+ DnsSearch []string
+ ExtraHosts []string
+ VolumesFrom []string
+ Devices []DeviceMapping
+ NetworkMode string
+ IpcMode string
+ PidMode string
+ UTSMode string
+ CapAdd []string
+ CapDrop []string
+ GroupAdd []string
+ RestartPolicy RestartPolicy
+ SecurityOpt []string
+ ReadonlyRootfs bool
+ Ulimits []Ulimit
+ LogConfig LogConfig
+ CgroupParent string
+ ConsoleSize [2]int
+ VolumeDriver string
+ OomScoreAdj int
+ Tmpfs map[string]string
+ ShmSize int64
+ BlkioWeightDevice []WeightDevice
+ BlkioDeviceReadBps []ThrottleDevice
+ BlkioDeviceWriteBps []ThrottleDevice
+ BlkioDeviceReadIOps []ThrottleDevice
+ BlkioDeviceWriteIOps []ThrottleDevice
+}
+
+type WeightDevice struct {
+ Path string
+ Weight uint16
+}
+
+type ThrottleDevice struct {
+ Path string
+ Rate uint64
+}
+
+type DeviceMapping struct {
+ PathOnHost string `json:"PathOnHost"`
+ PathInContainer string `json:"PathInContainer"`
+ CgroupPermissions string `json:"CgroupPermissions"`
+}
+
+type ExecConfig struct {
+ AttachStdin bool
+ AttachStdout bool
+ AttachStderr bool
+ Tty bool
+ Cmd []string
+ Container string
+ Detach bool
+}
+
+type LogOptions struct {
+ Follow bool
+ Stdout bool
+ Stderr bool
+ Timestamps bool
+ Tail int64
+}
+
+type AttachOptions struct {
+ Logs bool
+ Stream bool
+ Stdin bool
+ Stdout bool
+ Stderr bool
+}
+
+type MonitorEventsFilters struct {
+ Event string `json:",omitempty"`
+ Image string `json:",omitempty"`
+ Container string `json:",omitempty"`
+}
+
+type MonitorEventsOptions struct {
+ Since int
+ Until int
+ Filters *MonitorEventsFilters `json:",omitempty"`
+}
+
+type RestartPolicy struct {
+ Name string
+ MaximumRetryCount int64
+}
+
+type PortBinding struct {
+ HostIp string
+ HostPort string
+}
+
+type State struct {
+ Running bool
+ Paused bool
+ Restarting bool
+ OOMKilled bool
+ Dead bool
+ Pid int
+ ExitCode int
+ Error string // contains last known error when starting the container
+ StartedAt time.Time
+ FinishedAt time.Time
+ Ghost bool
+}
+
+// String returns a human-readable description of the state
+// Stoken from docker/docker/daemon/state.go
+func (s *State) String() string {
+ if s.Running {
+ if s.Paused {
+ return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
+ }
+ if s.Restarting {
+ return fmt.Sprintf("Restarting (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
+ }
+
+ return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
+ }
+
+ if s.Dead {
+ return "Dead"
+ }
+
+ if s.FinishedAt.IsZero() {
+ return ""
+ }
+
+ return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
+}
+
+// StateString returns a single string to describe state
+// Stoken from docker/docker/daemon/state.go
+func (s *State) StateString() string {
+ if s.Running {
+ if s.Paused {
+ return "paused"
+ }
+ if s.Restarting {
+ return "restarting"
+ }
+ return "running"
+ }
+
+ if s.Dead {
+ return "dead"
+ }
+
+ return "exited"
+}
+
+type ImageInfo struct {
+ Architecture string
+ Author string
+ Comment string
+ Config *ContainerConfig
+ Container string
+ ContainerConfig *ContainerConfig
+ Created time.Time
+ DockerVersion string
+ Id string
+ Os string
+ Parent string
+ Size int64
+ VirtualSize int64
+}
+
+type ImageSearch struct {
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ IsOfficial bool `json:"is_official,omitempty" yaml:"is_official,omitempty"`
+ IsAutomated bool `json:"is_automated,omitempty" yaml:"is_automated,omitempty"`
+ Name string `json:"name,omitempty" yaml:"name,omitempty"`
+ StarCount int `json:"star_count,omitempty" yaml:"star_count,omitempty"`
+}
+
+type ContainerInfo struct {
+ Id string
+ Created string
+ Path string
+ Name string
+ Args []string
+ ExecIDs []string
+ Config *ContainerConfig
+ State *State
+ Image string
+ NetworkSettings struct {
+ IPAddress string `json:"IpAddress"`
+ IPPrefixLen int `json:"IpPrefixLen"`
+ Gateway string
+ Bridge string
+ Ports map[string][]PortBinding
+ Networks map[string]*EndpointSettings
+ }
+ SysInitPath string
+ ResolvConfPath string
+ Volumes map[string]string
+ HostConfig *HostConfig
+}
+
+type ContainerChanges struct {
+ Path string
+ Kind int
+}
+
+type Port struct {
+ IP string
+ PrivatePort int
+ PublicPort int
+ Type string
+}
+
+// EndpointSettings stores the network endpoint details
+type EndpointSettings struct {
+ // Configurations
+ IPAMConfig *EndpointIPAMConfig
+ Links []string
+ Aliases []string
+ // Operational data
+ NetworkID string
+ EndpointID string
+ Gateway string
+ IPAddress string
+ IPPrefixLen int
+ IPv6Gateway string
+ GlobalIPv6Address string
+ GlobalIPv6PrefixLen int
+ MacAddress string
+}
+
+// NetworkingConfig represents the container's networking configuration for each of its interfaces
+// Carries the networink configs specified in the `docker run` and `docker network connect` commands
+type NetworkingConfig struct {
+ EndpointsConfig map[string]*EndpointSettings // Endpoint configs for each conencting network
+}
+
+type Container struct {
+ Id string
+ Names []string
+ Image string
+ Command string
+ Created int64
+ Status string
+ Ports []Port
+ SizeRw int64
+ SizeRootFs int64
+ Labels map[string]string
+ NetworkSettings struct {
+ Networks map[string]EndpointSettings
+ }
+}
+
+type Actor struct {
+ ID string
+ Attributes map[string]string
+}
+
+type Event struct {
+ Status string `json:"status,omitempty"`
+ ID string `json:"id,omitempty"`
+ From string `json:"from,omitempty"`
+
+ Type string
+ Action string
+ Actor Actor
+
+ Time int64 `json:"time,omitempty"`
+ TimeNano int64 `json:"timeNano,omitempty"`
+}
+
+type Version struct {
+ ApiVersion string
+ Arch string
+ GitCommit string
+ GoVersion string
+ KernelVersion string
+ Os string
+ Version string
+}
+
+type RespContainersCreate struct {
+ Id string
+ Warnings []string
+}
+
+type Image struct {
+ Created int64
+ Id string
+ Labels map[string]string
+ ParentId string
+ RepoDigests []string
+ RepoTags []string
+ Size int64
+ VirtualSize int64
+}
+
+// Info is the struct returned by /info
+// The API is currently in flux, so Debug, MemoryLimit, SwapLimit, and
+// IPv4Forwarding are interfaces because in docker 1.6.1 they are 0 or 1 but in
+// master they are bools.
+type Info struct {
+ ID string
+ Containers int64
+ Driver string
+ DriverStatus [][]string
+ ExecutionDriver string
+ Images int64
+ KernelVersion string
+ OperatingSystem string
+ NCPU int64
+ MemTotal int64
+ Name string
+ Labels []string
+ Debug interface{}
+ NFd int64
+ NGoroutines int64
+ SystemTime string
+ NEventsListener int64
+ InitPath string
+ InitSha1 string
+ IndexServerAddress string
+ MemoryLimit interface{}
+ SwapLimit interface{}
+ IPv4Forwarding interface{}
+ BridgeNfIptables bool
+ BridgeNfIp6tables bool
+ DockerRootDir string
+ HttpProxy string
+ HttpsProxy string
+ NoProxy string
+}
+
+type ImageDelete struct {
+ Deleted string
+ Untagged string
+}
+
+type StatsOrError struct {
+ Stats
+ Error error
+}
+
+type EventOrError struct {
+ Event
+ Error error
+}
+
+type WaitResult struct {
+ ExitCode int
+ Error error
+}
+
+type decodingResult struct {
+ result interface{}
+ err error
+}
+
+// The following are types for the API stats endpoint
+type ThrottlingData struct {
+ // Number of periods with throttling active
+ Periods uint64 `json:"periods"`
+ // Number of periods when the container hit its throttling limit.
+ ThrottledPeriods uint64 `json:"throttled_periods"`
+ // Aggregate time the container was throttled for in nanoseconds.
+ ThrottledTime uint64 `json:"throttled_time"`
+}
+
+// All CPU stats are aggregated since container inception.
+type CpuUsage struct {
+ // Total CPU time consumed.
+ // Units: nanoseconds.
+ TotalUsage uint64 `json:"total_usage"`
+ // Total CPU time consumed per core.
+ // Units: nanoseconds.
+ PercpuUsage []uint64 `json:"percpu_usage"`
+ // Time spent by tasks of the cgroup in kernel mode.
+ // Units: nanoseconds.
+ UsageInKernelmode uint64 `json:"usage_in_kernelmode"`
+ // Time spent by tasks of the cgroup in user mode.
+ // Units: nanoseconds.
+ UsageInUsermode uint64 `json:"usage_in_usermode"`
+}
+
+type CpuStats struct {
+ CpuUsage CpuUsage `json:"cpu_usage"`
+ SystemUsage uint64 `json:"system_cpu_usage"`
+ ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
+}
+
+type NetworkStats struct {
+ RxBytes uint64 `json:"rx_bytes"`
+ RxPackets uint64 `json:"rx_packets"`
+ RxErrors uint64 `json:"rx_errors"`
+ RxDropped uint64 `json:"rx_dropped"`
+ TxBytes uint64 `json:"tx_bytes"`
+ TxPackets uint64 `json:"tx_packets"`
+ TxErrors uint64 `json:"tx_errors"`
+ TxDropped uint64 `json:"tx_dropped"`
+}
+
+type MemoryStats struct {
+ Usage uint64 `json:"usage"`
+ MaxUsage uint64 `json:"max_usage"`
+ Stats map[string]uint64 `json:"stats"`
+ Failcnt uint64 `json:"failcnt"`
+ Limit uint64 `json:"limit"`
+}
+
+type BlkioStatEntry struct {
+ Major uint64 `json:"major"`
+ Minor uint64 `json:"minor"`
+ Op string `json:"op"`
+ Value uint64 `json:"value"`
+}
+
+type BlkioStats struct {
+ // number of bytes tranferred to and from the block device
+ IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive"`
+ IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive"`
+ IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive"`
+ IoServiceTimeRecursive []BlkioStatEntry `json:"io_service_time_recursive"`
+ IoWaitTimeRecursive []BlkioStatEntry `json:"io_wait_time_recursive"`
+ IoMergedRecursive []BlkioStatEntry `json:"io_merged_recursive"`
+ IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive"`
+ SectorsRecursive []BlkioStatEntry `json:"sectors_recursive"`
+}
+
+type Stats struct {
+ Read time.Time `json:"read"`
+ NetworkStats NetworkStats `json:"network,omitempty"`
+ CpuStats CpuStats `json:"cpu_stats,omitempty"`
+ MemoryStats MemoryStats `json:"memory_stats,omitempty"`
+ BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
+}
+
+type Ulimit struct {
+ Name string `json:"name"`
+ Soft uint64 `json:"soft"`
+ Hard uint64 `json:"hard"`
+}
+
+type LogConfig struct {
+ Type string `json:"type"`
+ Config map[string]string `json:"config"`
+}
+
+type BuildImage struct {
+ Config *ConfigFile
+ DockerfileName string
+ Context io.Reader
+ RemoteURL string
+ RepoName string
+ SuppressOutput bool
+ NoCache bool
+ Remove bool
+ ForceRemove bool
+ Pull bool
+ Memory int64
+ MemorySwap int64
+ CpuShares int64
+ CpuPeriod int64
+ CpuQuota int64
+ CpuSetCpus string
+ CpuSetMems string
+ CgroupParent string
+ BuildArgs map[string]string
+}
+
+type Volume struct {
+ Name string // Name is the name of the volume
+ Driver string // Driver is the Driver name used to create the volume
+ Mountpoint string // Mountpoint is the location on disk of the volume
+}
+
+type VolumesListResponse struct {
+ Volumes []*Volume // Volumes is the list of volumes being returned
+}
+
+type VolumeCreateRequest struct {
+ Name string // Name is the requested name of the volume
+ Driver string // Driver is the name of the driver that should be used to create the volume
+ DriverOpts map[string]string // DriverOpts holds the driver specific options to use for when creating the volume.
+}
+
+// IPAM represents IP Address Management
+type IPAM struct {
+ Driver string
+ Options map[string]string //Per network IPAM driver options
+ Config []IPAMConfig
+}
+
+// IPAMConfig represents IPAM configurations
+type IPAMConfig struct {
+ Subnet string `json:",omitempty"`
+ IPRange string `json:",omitempty"`
+ Gateway string `json:",omitempty"`
+ AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
+}
+
+// EndpointIPAMConfig represents IPAM configurations for the endpoint
+type EndpointIPAMConfig struct {
+ IPv4Address string `json:",omitempty"`
+ IPv6Address string `json:",omitempty"`
+}
+
+// NetworkResource is the body of the "get network" http response message
+type NetworkResource struct {
+ Name string
+ ID string `json:"Id"`
+ Scope string
+ Driver string
+ IPAM IPAM
+ //Internal bool
+ Containers map[string]EndpointResource
+ Options map[string]string
+}
+
+// EndpointResource contains network resources allocated and used for a container in a network
+type EndpointResource struct {
+ Name string
+ EndpointID string
+ MacAddress string
+ IPv4Address string
+ IPv6Address string
+}
+
+// NetworkCreate is the expected body of the "create network" http request message
+type NetworkCreate struct {
+ Name string
+ CheckDuplicate bool
+ Driver string
+ IPAM IPAM
+ Internal bool
+ Options map[string]string
+}
+
+// NetworkCreateResponse is the response message sent by the server for network create call
+type NetworkCreateResponse struct {
+ ID string `json:"Id"`
+ Warning string
+}
+
+// NetworkConnect represents the data to be used to connect a container to the network
+type NetworkConnect struct {
+ Container string
+}
+
+// NetworkDisconnect represents the data to be used to disconnect a container from the network
+type NetworkDisconnect struct {
+ Container string
+ Force bool
+}
diff --git a/go/src/gosetup/vendor/github.com/samalba/dockerclient/utils.go b/go/src/gosetup/vendor/github.com/samalba/dockerclient/utils.go
new file mode 100644
index 00000000..8a6b0d6e
--- /dev/null
+++ b/go/src/gosetup/vendor/github.com/samalba/dockerclient/utils.go
@@ -0,0 +1,41 @@
+package dockerclient
+
+import (
+ "crypto/tls"
+ "net"
+ "net/http"
+ "net/url"
+ "time"
+)
+
+type tcpFunc func(*net.TCPConn, time.Duration) error
+
+func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration, setUserTimeout tcpFunc) *http.Client {
+ httpTransport := &http.Transport{
+ TLSClientConfig: tlsConfig,
+ }
+
+ switch u.Scheme {
+ default:
+ httpTransport.Dial = func(proto, addr string) (net.Conn, error) {
+ conn, err := net.DialTimeout(proto, addr, timeout)
+ if tcpConn, ok := conn.(*net.TCPConn); ok && setUserTimeout != nil {
+ // Sender can break TCP connection if the remote side doesn't
+ // acknowledge packets within timeout
+ setUserTimeout(tcpConn, timeout)
+ }
+ return conn, err
+ }
+ case "unix":
+ socketPath := u.Path
+ unixDial := func(proto, addr string) (net.Conn, error) {
+ return net.DialTimeout("unix", socketPath, timeout)
+ }
+ httpTransport.Dial = unixDial
+ // Override the main URL object so the HTTP lib won't complain
+ u.Scheme = "http"
+ u.Host = "unix.sock"
+ u.Path = ""
+ }
+ return &http.Client{Transport: httpTransport}
+}
diff --git a/start.sh b/start.sh
index 73c9632b..26dae3fa 100755
--- a/start.sh
+++ b/start.sh
@@ -6,4 +6,9 @@ goproxy &> /srv/world/goproxy_out &
# start Minecraft C++ server
cd /srv/world
+
+# GOPROXY DEVELOPMENT: start cuberite as a daemon
+#../cuberite_server/Cuberite -d
../cuberite_server/Cuberite
+
+/bin/bash
\ No newline at end of file
diff --git a/world/Plugins/Docker/container.lua b/world/Plugins/Docker/container.lua
index 8bf8e689..1f624876 100644
--- a/world/Plugins/Docker/container.lua
+++ b/world/Plugins/Docker/container.lua
@@ -11,6 +11,7 @@ CONTAINER_STOPPED = 2
-- the Minecraft world
function NewContainer()
c = {
+ -- attributes
displayed = false,
x = 0,
z = 0,
@@ -19,18 +20,31 @@ function NewContainer()
imageRepo="",
imageTag="",
running=false,
+ networks={}, -- array of network objects
+ -- methods
init=Container.init,
setInfos=Container.setInfos,
destroy=Container.destroy,
display=Container.display,
updateMemSign=Container.updateMemSign,
updateCPUSign=Container.updateCPUSign,
- addGround=Container.addGround
+ addGround=Container.addGround,
+ connectNetwork=Container.connectNetwork
}
return c
end
-Container = {displayed = false, x = 0, z = 0, name="",id="",imageRepo="",imageTag="",running=false}
+Container = {
+ displayed = false,
+ x = 0,
+ z = 0,
+ name="",
+ id="",
+ imageRepo="",
+ imageTag="",
+ running=false,
+ networks={}
+ }
-- Container:init sets Container's position
function Container:init(x,z)
@@ -152,7 +166,6 @@ function Container:display(running)
setBlock(UpdateQueue,self.x+1,GROUND_LEVEL+3,self.z+1,E_BLOCK_LEVER,9)
end
-
-- remove button
setBlock(UpdateQueue,self.x+2,GROUND_LEVEL + 3,self.z + 2,E_BLOCK_WALLSIGN,E_META_CHEST_FACING_XM)
@@ -160,12 +173,10 @@ function Container:display(running)
setBlock(UpdateQueue,self.x+2,GROUND_LEVEL+3,self.z+3,E_BLOCK_STONE_BUTTON,E_BLOCK_BUTTON_XM)
-
-- door
-- Cuberite bug with Minecraft 1.8 apparently, doors are not displayed correctly
-- setBlock(UpdateQueue,self.x+2,GROUND_LEVEL+2,self.z,E_BLOCK_WOODEN_DOOR,E_META_CHEST_FACING_ZM)
-
for px=self.x, self.x+3
do
for pz=self.z, self.z+4
@@ -213,3 +224,23 @@ function Container:addGround()
end
end
end
+
+-- Container:connectNetwork
+function Container:connectNetwork(network)
+ -- check if the container is already connected to this network
+ found = false
+ for i=1, table.getn(self.networks) do
+ if self.networks[i].id == network.id then
+ found = true
+ break
+ end
+ end
+ if found == false then
+ -- TODO: gdevillele: support multiple networks per container
+ LOG("[CONTAINER] [connectNetwork] container is connected to a new network")
+ table.insert(self.networks, network)
+ setBlock(UpdateQueue, self.x+3, GROUND_LEVEL+5, self.z, E_BLOCK_WOOL, E_META_WOOL_RED)
+ else
+ -- container already know it is connected to this network, we do noting
+ end
+end
diff --git a/world/Plugins/Docker/docker.lua b/world/Plugins/Docker/docker.lua
index a87e2d19..5a2e8af6 100644
--- a/world/Plugins/Docker/docker.lua
+++ b/world/Plugins/Docker/docker.lua
@@ -10,6 +10,9 @@ SignsToUpdate = {}
-- in the "Containers" array to indicate that there is no container at an index
EmptyContainerSpace = {}
+-- array of docker networks objects
+Networks = {}
+
-- Tick is triggered by cPluginManager.HOOK_TICK
function Tick(TimeDelta)
UpdateQueue:update(MAX_BLOCK_UPDATE_PER_TICK)
@@ -17,13 +20,12 @@ end
-- Plugin initialization
function Initialize(Plugin)
- Plugin:SetName("Docker")
+ Plugin:SetName("Docker") -- set the name of the plugin
Plugin:SetVersion(1)
UpdateQueue = NewUpdateQueue()
-- Hooks
-
cPluginManager:AddHook(cPluginManager.HOOK_WORLD_STARTED, WorldStarted);
cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_JOINED, PlayerJoined);
cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_USING_BLOCK, PlayerUsingBlock);
@@ -35,17 +37,14 @@ function Initialize(Plugin)
cPluginManager:AddHook(cPluginManager.HOOK_TICK, Tick);
-- Command Bindings
-
cPluginManager.BindCommand("/docker", "*", DockerCommand, " - docker CLI commands")
-
Plugin:AddWebTab("Docker",HandleRequest_Docker)
-- make all players admin
cRankManager:SetDefaultRank("Admin")
-
- LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
-
+ LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() .. " plugin")
+ -- return true to tell Cuberite the plugin has been initialized successfully
return true
end
@@ -124,6 +123,40 @@ function destroyContainer(id)
end
end
+-- updateNetwork
+function updateNetwork(containerId, networkId, networkName, networkType)
+ LOG("[UPDATE NETWORK] network " .. networkName .. " (" .. networkId .. ") (" .. networkType .. ") now contains container " .. containerId)
+
+ -- create network object based on the function arguments
+ network = NewNetwork()
+ network:init(networkId, networkName, networkType)
+
+ -- first: check whether this network is already known
+ networkFound = false
+ for i=1, table.getn(Networks) do
+ -- if network is found
+ if Networks[i].id == networkId then
+ networkFound = true
+ LOG("[UPDATE NETWORK] network has been found")
+ break
+ end
+ end
+
+ -- second: if network is not found, we add it
+ if networkFound == false then
+ LOG("[UPDATE NETWORK] network has NOT been found, we add it to the list of networks")
+ table.insert(Networks, network)
+ end
+
+ -- third: update the container so it knows it is part of the network
+ for i=1, table.getn(Containers) do
+ if Containers[i] ~= EmptyContainerSpace and Containers[i].id == containerId then
+ -- tell container object, it is connected to a network
+ Containers[i]:connectNetwork(network)
+ end
+ end
+end
+
-- updateContainer accepts 3 different states: running, stopped, created
-- sometimes "start" events arrive before "create" ones
-- in this case, we just ignore the update
@@ -290,17 +323,29 @@ function DockerCommand(Split, Player)
end
-
+-- handle http requests received from the dockercraft goproxy
function HandleRequest_Docker(Request)
-
+
content = "[dockerclient]"
+ -- test if the request contains an "action" field
if Request.PostParams["action"] ~= nil then
+ -- retrieving the value of the "action" field
action = Request.PostParams["action"]
+ -- network actions
+ if action == "network_connect"
+ then
+ containerId = Request.PostParams["containerId"]
+ networkId = Request.PostParams["networkId"]
+ networkName = Request.PostParams["networkName"]
+ networkType = Request.PostParams["networkType"]
+ LOG("EVENT - network_connect "..containerId.." "..networkId.." "..networkName.." "..networkType)
+ updateNetwork(containerId, networkId, networkName, networkType)
+ end
+
-- receiving informations about one container
-
if action == "containerInfos"
then
LOG("EVENT - containerInfos")
@@ -373,12 +418,10 @@ function HandleRequest_Docker(Request)
updateStats(id,ram,cpu)
end
-
content = content .. "{action:\"" .. action .. "\"}"
else
content = content .. "{error:\"action requested\"}"
-
end
content = content .. "[/dockerclient]"
diff --git a/world/Plugins/Docker/network.lua b/world/Plugins/Docker/network.lua
new file mode 100644
index 00000000..b8abeb60
--- /dev/null
+++ b/world/Plugins/Docker/network.lua
@@ -0,0 +1,210 @@
+-- Network object is the representation of a Docker network
+-- in the Minecraft world
+
+-- NewNetwork returns a Network object,
+-- representing of a Docker network in
+-- the Minecraft world
+function NewNetwork()
+ c = {
+ id="",
+ name="",
+ type="",
+ -- methods
+ init=Network.init,
+ -- setInfos=Container.setInfos,
+ -- destroy=Container.destroy,
+ -- display=Container.display,
+ -- updateMemSign=Container.updateMemSign,
+ -- updateCPUSign=Container.updateCPUSign,
+ -- addGround=Container.addGround
+ }
+ return c
+end
+
+Network = {
+ id="",
+ name="",
+ type=""
+ }
+
+-- Network:init sets Network's properties
+function Network:init(id,name,type)
+ self.id = id
+ self.name = name
+ self.type = type
+end
+
+-- -- Container:setInfos sets Container's id, name, imageRepo,
+-- -- image tag and running state
+-- function Container:setInfos(id,name,imageRepo,imageTag,running)
+-- self.id = id
+-- self.name = name
+-- self.imageRepo = imageRepo
+-- self.imageTag = imageTag
+-- self.running = running
+-- end
+
+-- -- Container:destroy removes all blocks of the
+-- -- container, it won't be visible on the map anymore
+-- function Container:destroy(running)
+-- X = self.x+2
+-- Y = GROUND_LEVEL+2
+-- Z = self.z+2
+-- LOG("Exploding at X:" .. X .. " Y:" .. Y .. " Z:" .. Z)
+-- local World = cRoot:Get():GetDefaultWorld()
+-- World:BroadcastSoundEffect("random.explode", X, Y, Z, 1, 1)
+-- World:BroadcastParticleEffect("hugeexplosion",X, Y, Z, 0, 0, 0, 1, 1)
+
+-- -- if a block is removed before it's button/lever/sign, that object will drop
+-- -- and the player can collect it. Remove these first
+
+-- -- lever
+-- digBlock(UpdateQueue,self.x+1,GROUND_LEVEL+3,self.z+1)
+-- -- signs
+-- digBlock(UpdateQueue,self.x+3,GROUND_LEVEL+2,self.z-1)
+-- digBlock(UpdateQueue,self.x,GROUND_LEVEL+2,self.z-1)
+-- digBlock(UpdateQueue,self.x+1,GROUND_LEVEL+2,self.z-1)
+-- -- torch
+-- digBlock(UpdateQueue,self.x+1,GROUND_LEVEL+3,self.z+1)
+-- --button
+-- digBlock(UpdateQueue,self.x+2,GROUND_LEVEL+3,self.z+2)
+
+-- -- rest of the blocks
+-- for py = GROUND_LEVEL+1, GROUND_LEVEL+4
+-- do
+-- for px=self.x-1, self.x+4
+-- do
+-- for pz=self.z-1, self.z+5
+-- do
+-- digBlock(UpdateQueue,px,py,pz)
+-- end
+-- end
+-- end
+-- end
+
+-- -- Container:display displays all Container's blocks
+-- -- Blocks will be blue if the container is running,
+-- -- orange otherwise.
+-- function Container:display(running)
+
+-- metaPrimaryColor = E_META_WOOL_LIGHTBLUE
+-- metaSecondaryColor = E_META_WOOL_BLUE
+
+-- if running == false
+-- then
+-- metaPrimaryColor = E_META_WOOL_ORANGE
+-- metaSecondaryColor = E_META_WOOL_RED
+-- end
+
+-- self.displayed = true
+
+-- for px=self.x, self.x+3
+-- do
+-- for pz=self.z, self.z+4
+-- do
+-- setBlock(UpdateQueue,px,GROUND_LEVEL + 1,pz,E_BLOCK_WOOL,metaPrimaryColor)
+-- end
+-- end
+
+-- for py = GROUND_LEVEL+2, GROUND_LEVEL+3
+-- do
+-- setBlock(UpdateQueue,self.x+1,py,self.z,E_BLOCK_WOOL,metaPrimaryColor)
+
+-- -- leave empty space for the door
+-- -- setBlock(UpdateQueue,self.x+2,py,self.z,E_BLOCK_WOOL,metaPrimaryColor)
+
+-- setBlock(UpdateQueue,self.x,py,self.z,E_BLOCK_WOOL,metaPrimaryColor)
+-- setBlock(UpdateQueue,self.x+3,py,self.z,E_BLOCK_WOOL,metaPrimaryColor)
+
+-- setBlock(UpdateQueue,self.x,py,self.z+1,E_BLOCK_WOOL,metaSecondaryColor)
+-- setBlock(UpdateQueue,self.x+3,py,self.z+1,E_BLOCK_WOOL,metaSecondaryColor)
+
+-- setBlock(UpdateQueue,self.x,py,self.z+2,E_BLOCK_WOOL,metaPrimaryColor)
+-- setBlock(UpdateQueue,self.x+3,py,self.z+2,E_BLOCK_WOOL,metaPrimaryColor)
+
+-- setBlock(UpdateQueue,self.x,py,self.z+3,E_BLOCK_WOOL,metaSecondaryColor)
+-- setBlock(UpdateQueue,self.x+3,py,self.z+3,E_BLOCK_WOOL,metaSecondaryColor)
+
+-- setBlock(UpdateQueue,self.x,py,self.z+4,E_BLOCK_WOOL,metaPrimaryColor)
+-- setBlock(UpdateQueue,self.x+3,py,self.z+4,E_BLOCK_WOOL,metaPrimaryColor)
+
+-- setBlock(UpdateQueue,self.x+1,py,self.z+4,E_BLOCK_WOOL,metaPrimaryColor)
+-- setBlock(UpdateQueue,self.x+2,py,self.z+4,E_BLOCK_WOOL,metaPrimaryColor)
+-- end
+
+-- -- torch
+-- setBlock(UpdateQueue,self.x+1,GROUND_LEVEL+3,self.z+3,E_BLOCK_TORCH,E_META_TORCH_ZP)
+
+-- -- start / stop lever
+-- setBlock(UpdateQueue,self.x+1,GROUND_LEVEL + 3,self.z + 2,E_BLOCK_WALLSIGN,E_META_CHEST_FACING_XP)
+-- updateSign(UpdateQueue,self.x+1,GROUND_LEVEL + 3,self.z + 2,"","START/STOP","---->","",2)
+
+
+-- if running
+-- then
+-- setBlock(UpdateQueue,self.x+1,GROUND_LEVEL+3,self.z+1,E_BLOCK_LEVER,1)
+-- else
+-- setBlock(UpdateQueue,self.x+1,GROUND_LEVEL+3,self.z+1,E_BLOCK_LEVER,9)
+-- end
+
+
+-- -- remove button
+
+-- setBlock(UpdateQueue,self.x+2,GROUND_LEVEL + 3,self.z + 2,E_BLOCK_WALLSIGN,E_META_CHEST_FACING_XM)
+-- updateSign(UpdateQueue,self.x+2,GROUND_LEVEL + 3,self.z + 2,"","REMOVE","---->","",2)
+
+-- setBlock(UpdateQueue,self.x+2,GROUND_LEVEL+3,self.z+3,E_BLOCK_STONE_BUTTON,E_BLOCK_BUTTON_XM)
+
+
+-- -- door
+-- -- Cuberite bug with Minecraft 1.8 apparently, doors are not displayed correctly
+-- -- setBlock(UpdateQueue,self.x+2,GROUND_LEVEL+2,self.z,E_BLOCK_WOODEN_DOOR,E_META_CHEST_FACING_ZM)
+
+
+-- for px=self.x, self.x+3
+-- do
+-- for pz=self.z, self.z+4
+-- do
+-- setBlock(UpdateQueue,px,GROUND_LEVEL + 4,pz,E_BLOCK_WOOL,metaPrimaryColor)
+-- end
+-- end
+
+-- setBlock(UpdateQueue,self.x+3,GROUND_LEVEL + 2,self.z - 1,E_BLOCK_WALLSIGN,E_META_CHEST_FACING_ZM)
+-- updateSign(UpdateQueue,self.x+3,GROUND_LEVEL + 2,self.z - 1,string.sub(self.id,1,8),self.name,self.imageRepo,self.imageTag,2)
+
+-- -- Mem sign
+-- setBlock(UpdateQueue,self.x,GROUND_LEVEL + 2,self.z - 1,E_BLOCK_WALLSIGN,E_META_CHEST_FACING_ZM)
+
+-- -- CPU sign
+-- setBlock(UpdateQueue,self.x+1,GROUND_LEVEL + 2,self.z - 1,E_BLOCK_WALLSIGN,E_META_CHEST_FACING_ZM)
+-- end
+
+
+-- -- Container:updateMemSign updates the mem usage
+-- -- value displayed on Container's sign
+-- function Container:updateMemSign(s)
+-- updateSign(UpdateQueue,self.x,GROUND_LEVEL + 2,self.z - 1,"Mem usage","",s,"")
+-- end
+
+-- -- Container:updateCPUSign updates the mem usage
+-- -- value displayed on Container's sign
+-- function Container:updateCPUSign(s)
+-- updateSign(UpdateQueue,self.x+1,GROUND_LEVEL + 2,self.z - 1,"CPU usage","",s,"")
+-- end
+
+-- -- Container:addGround creates ground blocks
+-- -- necessary to display the container
+-- function Container:addGround()
+-- if GROUND_MIN_X > self.x - 2
+-- then
+-- OLD_GROUND_MIN_X = GROUND_MIN_X
+-- GROUND_MIN_X = self.x - 2
+-- for x= GROUND_MIN_X, OLD_GROUND_MIN_X
+-- do
+-- for z=GROUND_MIN_Z,GROUND_MAX_Z
+-- do
+-- setBlock(UpdateQueue,x,y,z,E_BLOCK_WOOL,E_META_WOOL_WHITE)
+-- end
+-- end
+-- end
+-- end