Merge pull request #88 from littlebeer2100/components

Components
This commit is contained in:
alex.fan
2018-06-16 18:37:00 +08:00
committed by GitHub
281 changed files with 10769 additions and 6185 deletions

34
Gopkg.lock generated
View File

@@ -7,6 +7,12 @@
revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f" revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f"
version = "v0.4.7" version = "v0.4.7"
[[projects]]
name = "github.com/Sirupsen/logrus"
packages = ["."]
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
version = "v1.0.5"
[[projects]] [[projects]]
name = "github.com/coreos/etcd" name = "github.com/coreos/etcd"
packages = [ packages = [
@@ -32,7 +38,6 @@
revision = "749f6afb4572201e3c37325d0ffedb6f32be8950" revision = "749f6afb4572201e3c37325d0ffedb6f32be8950"
[[projects]] [[projects]]
branch = "master"
name = "github.com/docker/docker" name = "github.com/docker/docker"
packages = [ packages = [
"api", "api",
@@ -47,13 +52,17 @@
"api/types/registry", "api/types/registry",
"api/types/strslice", "api/types/strslice",
"api/types/swarm", "api/types/swarm",
"api/types/swarm/runtime",
"api/types/time", "api/types/time",
"api/types/versions", "api/types/versions",
"api/types/volume", "api/types/volume",
"client" "client",
"pkg/ioutils",
"pkg/longpath",
"pkg/system",
"pkg/tlsconfig"
] ]
revision = "de0abf4315fd1d737aedc2e9f410c8125ad1a7fc" revision = "90d35abf7b3535c1c319c872900fbd76374e521c"
version = "v17.05.0-ce-rc3"
[[projects]] [[projects]]
branch = "master" branch = "master"
@@ -71,6 +80,12 @@
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c" revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
version = "v0.3.3" version = "v0.3.3"
[[projects]]
branch = "master"
name = "github.com/docker/libtrust"
packages = ["."]
revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20"
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "github.com/docker/spdystream" name = "github.com/docker/spdystream"
@@ -200,15 +215,6 @@
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf" revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
version = "v1.0.0-rc1" version = "v1.0.0-rc1"
[[projects]]
name = "github.com/opencontainers/image-spec"
packages = [
"specs-go",
"specs-go/v1"
]
revision = "d60099175f88c47cd379c4738d158884749ed235"
version = "v1.0.1"
[[projects]] [[projects]]
name = "github.com/pkg/errors" name = "github.com/pkg/errors"
packages = ["."] packages = ["."]
@@ -492,6 +498,6 @@
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "cd655ecbe7567a163c75d4b4fb9f0e51f1b6a8c94cfe28a2542a82990e610741" inputs-digest = "a1aa0da3f3fabe007676d84dfb6b91542cb3f3d652bf70e982ee8451e094c0e4"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@@ -31,7 +31,7 @@
[[constraint]] [[constraint]]
name = "github.com/docker/docker" name = "github.com/docker/docker"
branch = "master" version = "v17.05.0-ce"
[[constraint]] [[constraint]]
name = "github.com/emicklei/go-restful" name = "github.com/emicklei/go-restful"

View File

@@ -31,6 +31,10 @@ func Register(ws *restful.WebService, subPath string) {
Consumes(restful.MIME_JSON, restful.MIME_XML). Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON) Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/{namespace}").To(handleGetComponentsByNamespace).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
} }
//get all components //get all components
@@ -50,3 +54,22 @@ func handleGetComponents(request *restful.Request, response *restful.Response) {
} }
} }
//get components from ns
func handleGetComponentsByNamespace(request *restful.Request, response *restful.Response) {
ns := request.PathParameter("namespace")
result, err := models.GetComponentsByNamespace(ns)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(result)
}
}

View File

@@ -17,7 +17,6 @@ limitations under the License.
package models package models
import ( import (
"strings"
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
@@ -31,208 +30,46 @@ const OPENPITRIX = "openpitrix-system"
const ISTIO = "istio-system" const ISTIO = "istio-system"
const KUBESPHERE = "kubesphere-system" const KUBESPHERE = "kubesphere-system"
type ComponentsCount struct {
KubernetesCount int `json:"kubernetesCount"`
OpenpitrixCount int `json:"openpitrixCount"`
KubesphereCount int `json:"kubesphereCount"`
IstioCount int `json:"istioCount"`
}
type Components struct { type Components struct {
Name string `json:"name"` Name string `json:"name"`
Version string `json:"version"`
Kind string `json:"kind"`
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
Label interface{} `json:"label"`
Replicas int `json:"replicas"`
HealthStatus string `json:"healthStatus"`
SelfLink string `json:"selfLink"` SelfLink string `json:"selfLink"`
UpdateTime time.Time `json:"updateTime"` Label interface{} `json:"label"`
HealthStatus string `json:"healthStatus"`
CreateTime time.Time `json:"updateTime"`
} }
/*** /***
* get all components from k8s and kubesphere system, * get all components from k8s and kubesphere system
* there are master component, node component,addons component , kubesphere component
* *
*/ */
func GetComponents() ([]Components, error) { func GetComponents() (map[string]interface{}, error) {
result := make([]Components, 0) result := make(map[string]interface{})
componentsList := make([]Components, 0)
k8sClient := client.NewK8sClient() k8sClient := client.NewK8sClient()
label := "tier=control-plane" var count ComponentsCount
var components Components
label := "kubernetes.io/cluster-service=true"
option := meta_v1.ListOptions{ option := meta_v1.ListOptions{
LabelSelector: label, LabelSelector: label,
} }
podlists, err := k8sClient.CoreV1().Pods(KUBESYSTEM).List(option)
if err != nil {
glog.Error(err)
return result, err
}
var components Components
templates := []string{"kube-apiserver", "etcd", "kube-scheduler", "kube-controller-manager", "cloud-controller-manager"}
if len(podlists.Items) > 0 {
for _, pod := range podlists.Items {
for _, template := range templates {
if strings.Contains(pod.Name, template) {
components.Name = template
components.Kind = "Pod"
components.SelfLink = pod.SelfLink
components.Label = pod.Labels
components.Namespace = pod.Namespace
version := strings.Split(pod.Spec.Containers[0].Image, ":")
if len(version) < 2 {
components.Version = "latest"
} else {
components.Version = version[1]
}
components.Replicas = 1
if pod.Status.Phase == "Running" {
components.HealthStatus = "health"
} else {
components.HealthStatus = "unhealth"
}
components.UpdateTime = pod.Status.Conditions[0].LastTransitionTime.Time
result = append(result, components)
}
}
}
}
label = "component=kube-addon-manager"
option.LabelSelector = label
kubeaddon, err := k8sClient.CoreV1().Pods(KUBESYSTEM).List(option)
if err != nil {
glog.Error(err)
return result, err
}
if len(kubeaddon.Items) > 0 {
for _, pod := range kubeaddon.Items {
components.Name = "kube-addon-manager"
components.Kind = "Pod"
components.SelfLink = pod.SelfLink
components.Label = pod.Labels
components.Namespace = pod.Namespace
version := strings.Split(pod.Spec.Containers[0].Image, ":")
if len(version) < 2 {
components.Version = "latest"
} else {
components.Version = version[1]
}
components.Replicas = 1
if pod.Status.Phase == "Running" {
components.HealthStatus = "health"
} else {
components.HealthStatus = "unhealth"
}
components.UpdateTime = pod.Status.Conditions[0].LastTransitionTime.Time
result = append(result, components)
}
}
option.LabelSelector = ""
dsList, err := k8sClient.AppsV1beta2().DaemonSets(KUBESYSTEM).List(option)
if err != nil {
glog.Error(err)
return result, err
}
templates = []string{"flannel", "kube-proxy", "calico"}
if len(dsList.Items) > 0 {
for _, ds := range dsList.Items {
for _, template := range templates {
if strings.Contains(ds.Name, template) {
components.Name = ds.Name
components.Kind = "Daemonset"
components.SelfLink = ds.SelfLink
components.Label = ds.Spec.Selector.MatchLabels
components.Namespace = ds.Namespace
version := strings.Split(ds.Spec.Template.Spec.Containers[0].Image, ":")
if len(version) < 2 {
components.Version = "latest"
} else {
components.Version = version[1]
}
components.UpdateTime = ds.CreationTimestamp.Time
components.Replicas = int(ds.Status.DesiredNumberScheduled)
if ds.Status.NumberAvailable == ds.Status.DesiredNumberScheduled {
components.HealthStatus = "health"
} else {
components.HealthStatus = "unhealth"
}
result = append(result, components)
}
}
}
}
templates = []string{"kube-dns", "heapster", "monitoring-influxdb", "iam", "openpitrix", "istio", "kubesphere"}
namespaces := []string{KUBESYSTEM, OPENPITRIX, ISTIO, KUBESPHERE} namespaces := []string{KUBESYSTEM, OPENPITRIX, ISTIO, KUBESPHERE}
for _, ns := range namespaces { for _, ns := range namespaces {
deployList, err := k8sClient.AppsV1beta1().Deployments(ns).List(option) if ns != KUBESYSTEM {
option.LabelSelector = ""
}
servicelists, err := k8sClient.CoreV1().Services(ns).List(option)
if err != nil { if err != nil {
@@ -241,34 +78,61 @@ func GetComponents() ([]Components, error) {
return result, err return result, err
} }
if len(deployList.Items) > 0 { if len(servicelists.Items) > 0 {
for _, dm := range deployList.Items { for _, service := range servicelists.Items {
for _, template := range templates { switch ns {
if strings.Contains(dm.Name, template) { case KUBESYSTEM:
count.KubernetesCount++
case OPENPITRIX:
count.OpenpitrixCount++
case KUBESPHERE:
count.KubesphereCount++
components.Name = dm.Name default:
components.Kind = "Deployment" count.IstioCount++
components.SelfLink = dm.SelfLink }
components.Label = dm.Spec.Selector.MatchLabels
components.Namespace = dm.Namespace
components.Replicas = int(dm.Status.Replicas)
version := strings.Split(dm.Spec.Template.Spec.Containers[0].Image, ":")
if len(version) < 2 {
components.Version = "latest" components.Name = service.Name
components.Namespace = service.Namespace
components.CreateTime = service.CreationTimestamp.Time
components.Label = service.Spec.Selector
components.SelfLink = service.SelfLink
label := service.Spec.Selector
combination := ""
for key, val := range label {
labelstr := key + "=" + val
if combination == "" {
combination = labelstr
} else { } else {
components.Version = version[1] combination = combination + "," + labelstr
} }
components.UpdateTime = dm.Status.Conditions[0].LastUpdateTime.Time }
option := meta_v1.ListOptions{
LabelSelector: combination,
}
podsList, err := k8sClient.CoreV1().Pods(ns).List(option)
if dm.Status.AvailableReplicas == dm.Status.Replicas { if err != nil {
glog.Error(err)
return result, err
}
if len(podsList.Items) > 0 {
for _, pod := range podsList.Items {
if pod.Status.Phase == "Running" {
components.HealthStatus = "health" components.HealthStatus = "health"
@@ -278,18 +142,108 @@ func GetComponents() ([]Components, error) {
} }
}
}
componentsList = append(componentsList, components)
}
}
}
result["count"] = count
result["item"] = componentsList
return result, nil
}
func GetComponentsByNamespace(ns string) ([]Components, error) {
result := make([]Components, 0)
k8sClient := client.NewK8sClient()
var components Components
label := "kubernetes.io/cluster-service=true"
option := meta_v1.ListOptions{
LabelSelector: label,
}
if ns != KUBESYSTEM {
option.LabelSelector = ""
}
servicelists, err := k8sClient.CoreV1().Services(ns).List(option)
if err != nil {
glog.Error(err)
return result, err
}
if len(servicelists.Items) > 0 {
for _, service := range servicelists.Items {
components.Name = service.Name
components.Namespace = service.Namespace
components.CreateTime = service.CreationTimestamp.Time
components.SelfLink = service.SelfLink
components.Label = service.Spec.Selector
label := service.Spec.Selector
combination := ""
for key, val := range label {
labelstr := key + "=" + val
if combination == "" {
combination = labelstr
} else {
combination = combination + "," + labelstr
}
}
option := meta_v1.ListOptions{
LabelSelector: combination,
}
podsList, err := k8sClient.CoreV1().Pods(ns).List(option)
if err != nil {
glog.Error(err)
return result, err
}
if len(podsList.Items) > 0 {
for _, pod := range podsList.Items {
if pod.Status.Phase == "Running" {
components.HealthStatus = "health"
} else {
components.HealthStatus = "unhealth"
}
}
}
result = append(result, components) result = append(result, components)
} }
} }
}
}
}
return result, nil return result, nil
} }

View File

@@ -88,7 +88,7 @@ func RegistryLoginAuth(authinfo AuthInfo) ValidationMsg {
datastr := []byte(authinfo.Username + ":" + authinfo.Password) datastr := []byte(authinfo.Username + ":" + authinfo.Password)
auth := base64.StdEncoding.EncodeToString(datastr) auth := base64.StdEncoding.EncodeToString(datastr)
ctx := context.Background() ctx := context.Background()
cli, err := client.NewClientWithOpts() cli, err := client.NewEnvClient()
if err != nil { if err != nil {

View File

@@ -27,6 +27,7 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
policy "k8s.io/api/policy/v1beta1" policy "k8s.io/api/policy/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
"kubesphere.io/kubesphere/pkg/client" "kubesphere.io/kubesphere/pkg/client"
kubeclient "kubesphere.io/kubesphere/pkg/client" kubeclient "kubesphere.io/kubesphere/pkg/client"
@@ -265,9 +266,29 @@ func DrainNode(nodename string) (msg constants.MessageResponse, err error) {
return msg, err return msg, err
} }
} }
}
data := []byte(" {\"spec\":{\"unschedulable\":true}}")
nodestatus, err := k8sclient.CoreV1().Nodes().Patch(nodename, types.StrategicMergePatchType, data)
if err != nil {
glog.Fatal(err)
return msg, err
} }
if nodestatus.Spec.Unschedulable {
msg.Message = fmt.Sprintf("success") msg.Message = fmt.Sprintf("success")
} else {
glog.Fatal(err)
return msg, err
}
return msg, nil return msg, nil
} }

1
vendor/github.com/Sirupsen/logrus/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
logrus

15
vendor/github.com/Sirupsen/logrus/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,15 @@
language: go
go:
- 1.6.x
- 1.7.x
- 1.8.x
- tip
env:
- GOMAXPROCS=4 GORACE=halt_on_error=1
install:
- go get github.com/stretchr/testify/assert
- go get gopkg.in/gemnasium/logrus-airbrake-hook.v2
- go get golang.org/x/sys/unix
- go get golang.org/x/sys/windows
script:
- go test -race -v ./...

123
vendor/github.com/Sirupsen/logrus/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,123 @@
# 1.0.5
* Fix hooks race (#707)
* Fix panic deadlock (#695)
# 1.0.4
* Fix race when adding hooks (#612)
* Fix terminal check in AppEngine (#635)
# 1.0.3
* Replace example files with testable examples
# 1.0.2
* bug: quote non-string values in text formatter (#583)
* Make (*Logger) SetLevel a public method
# 1.0.1
* bug: fix escaping in text formatter (#575)
# 1.0.0
* Officially changed name to lower-case
* bug: colors on Windows 10 (#541)
* bug: fix race in accessing level (#512)
# 0.11.5
* feature: add writer and writerlevel to entry (#372)
# 0.11.4
* bug: fix undefined variable on solaris (#493)
# 0.11.3
* formatter: configure quoting of empty values (#484)
* formatter: configure quoting character (default is `"`) (#484)
* bug: fix not importing io correctly in non-linux environments (#481)
# 0.11.2
* bug: fix windows terminal detection (#476)
# 0.11.1
* bug: fix tty detection with custom out (#471)
# 0.11.0
* performance: Use bufferpool to allocate (#370)
* terminal: terminal detection for app-engine (#343)
* feature: exit handler (#375)
# 0.10.0
* feature: Add a test hook (#180)
* feature: `ParseLevel` is now case-insensitive (#326)
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
* performance: avoid re-allocations on `WithFields` (#335)
# 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)

21
vendor/github.com/Sirupsen/logrus/LICENSE generated vendored Normal file
View File

@@ -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.

511
vendor/github.com/Sirupsen/logrus/README.md generated vendored Normal file
View File

@@ -0,0 +1,511 @@
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus)
Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger.
**Seeing weird case-sensitive problems?** It's in the past been possible to
import Logrus as both upper- and lower-case. Due to the Go package environment,
this caused issues in the community and we needed a standard. Some environments
experienced problems with the upper-case variant, so the lower-case was decided.
Everything using `logrus` will need to use the lower-case:
`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
To fix Glide, see [these
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
For an in-depth explanation of the casing issue, see [this
comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276).
**Are you interested in assisting in maintaining Logrus?** Currently I have a
lot of obligations, and I am unable to provide Logrus with the maintainership it
needs. If you'd like to help, please reach out to me at `simon at author's
username dot com`.
Nicely color-coded in development (when a TTY is attached, otherwise just
plain text):
![Colored](http://i.imgur.com/PY7qMwd.png)
With `log.SetFormatter(&log.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.SetFormatter(&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
```
#### Case-sensitivity
The organization's name was changed to lower-case--and this will not be changed
back. If you are getting import conflicts due to case sensitivity, please use
the lower-case import: `github.com/sirupsen/logrus`.
#### 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 stdout instead of the default stderr
// Can be any io.Writer, see below for File example
log.SetOutput(os.Stdout)
// 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 (
"os"
"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.Stdout
// You could set this to any `io.Writer` such as a file
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
// if err == nil {
// log.Out = file
// } else {
// log.Info("Failed to log to file, using default stderr")
// }
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
}
```
#### Fields
Logrus encourages careful, structured logging through 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.
#### Default Fields
Often it's helpful to have fields _always_ attached to log statements in an
application or parts of one. For example, you may want to always log the
`request_id` and `user_ip` in the context of a request. Instead of writing
`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on
every line, you can create a `logrus.Entry` to pass around instead:
```go
requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
requestLogger.Info("something happened on that request") # will log request_id and user_ip
requestLogger.Warn("something not great happened")
```
#### 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 "airbrake"
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 "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. |
| [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. |
| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
| [Application Insights](https://github.com/jjcollinge/logrus-appinsights) | Hook for logging to [Application Insights](https://azure.microsoft.com/en-us/services/application-insights/)
| [AzureTableHook](https://github.com/kpfaulkner/azuretablehook/) | Hook for logging to Azure Table Storage|
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) |
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
| [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/)
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) |
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) |
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
| [KafkaLogrus](https://github.com/tracer0tong/kafkalogrus) | Hook for logging to Kafka |
| [Kafka REST Proxy](https://github.com/Nordstrom/logrus-kafka-rest-proxy) | Hook for logging to [Kafka REST Proxy](https://docs.confluent.io/current/kafka-rest/docs) |
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
| [Logbeat](https://github.com/macandmia/logbeat) | Hook for logging to [Opbeat](https://opbeat.com/) |
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) |
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
| [Promrus](https://github.com/weaveworks/promrus) | Expose number of log messages as [Prometheus](https://prometheus.io/) metrics |
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
| [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. |
| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. |
| [Telegram](https://github.com/rossmcdonald/telegram_hook) | Hook for logging errors to [Telegram](https://telegram.org/) |
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
| [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) |
#### 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`. For Windows, see
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
* `logrus.JSONFormatter`. Logs fields as JSON.
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
Third party logging formatters:
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
* [`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`.
This means that we can override the standard library logger easily:
```go
logger := logrus.New()
logger.Formatter = &logrus.JSONFormatter{}
// Use logrus for standard log output
// Note that `log` here references stdlib's log
// Not logrus imported under the name `log`.
log.SetOutput(logger.Writer())
```
#### 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.|
|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
#### 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
import(
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"testing"
)
func TestSomething(t*testing.T){
logger, hook := test.NewNullLogger()
logger.Error("Helloerror")
assert.Equal(t, 1, len(hook.Entries))
assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level)
assert.Equal(t, "Helloerror", hook.LastEntry().Message)
hook.Reset()
assert.Nil(t, hook.LastEntry())
}
```
#### Fatal handlers
Logrus can register one or more functions that will be called when any `fatal`
level message is logged. The registered handlers will be executed before
logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need
to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
```
...
handler := func() {
// gracefully shutdown something...
}
logrus.RegisterExitHandler(handler)
...
```
#### Thread safety
By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
Situation when locking is not needed includes:
* You have no hooks registered, or hooks calling is already thread-safe.
* Writing to logger.Out is already thread-safe, for example:
1) logger.Out is protected by locks.
2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing)
(Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)

64
vendor/github.com/Sirupsen/logrus/alt_exit.go generated vendored Normal file
View File

@@ -0,0 +1,64 @@
package logrus
// The following code was sourced and modified from the
// https://github.com/tebeka/atexit package governed by the following license:
//
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
//
// 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.
import (
"fmt"
"os"
)
var handlers = []func(){}
func runHandler(handler func()) {
defer func() {
if err := recover(); err != nil {
fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
}
}()
handler()
}
func runHandlers() {
for _, handler := range handlers {
runHandler(handler)
}
}
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
func Exit(code int) {
runHandlers()
os.Exit(code)
}
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
// all handlers. The handlers will also be invoked when any Fatal log entry is
// made.
//
// This method is useful when a caller wishes to use logrus to log a fatal
// message but also needs to gracefully shutdown. An example usecase could be
// closing database connections, or sending a alert that the application is
// closing.
func RegisterExitHandler(handler func()) {
handlers = append(handlers, handler)
}

14
vendor/github.com/Sirupsen/logrus/appveyor.yml generated vendored Normal file
View File

@@ -0,0 +1,14 @@
version: "{build}"
platform: x64
clone_folder: c:\gopath\src\github.com\sirupsen\logrus
environment:
GOPATH: c:\gopath
branches:
only:
- master
install:
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- go version
build_script:
- go get -t
- go test

26
vendor/github.com/Sirupsen/logrus/doc.go generated vendored Normal file
View File

@@ -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

288
vendor/github.com/Sirupsen/logrus/entry.go generated vendored Normal file
View File

@@ -0,0 +1,288 @@
package logrus
import (
"bytes"
"fmt"
"os"
"sync"
"time"
)
var bufferPool *sync.Pool
func init() {
bufferPool = &sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
}
// 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
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
Level Level
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
Message string
// When formatter is called in entry.log(), an Buffer may be set to entry
Buffer *bytes.Buffer
}
func NewEntry(logger *Logger) *Entry {
return &Entry{
Logger: logger,
// Default is three fields, give a little extra room
Data: make(Fields, 5),
}
}
// Returns the string representation from the reader and ultimately the
// formatter.
func (entry *Entry) String() (string, error) {
serialized, err := entry.Logger.Formatter.Format(entry)
if err != nil {
return "", err
}
str := string(serialized)
return str, nil
}
// 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 := make(Fields, len(entry.Data)+len(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) {
var buffer *bytes.Buffer
entry.Time = time.Now()
entry.Level = level
entry.Message = msg
entry.fireHooks()
buffer = bufferPool.Get().(*bytes.Buffer)
buffer.Reset()
defer bufferPool.Put(buffer)
entry.Buffer = buffer
entry.write()
entry.Buffer = nil
// 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)
}
}
// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) fireHooks() {
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
err := entry.Logger.Hooks.Fire(entry.Level, &entry)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
}
}
func (entry *Entry) write() {
serialized, err := entry.Logger.Formatter.Format(entry)
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
} else {
_, err = entry.Logger.Out.Write(serialized)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
}
}
}
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...))
}
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...))
}
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...))
}
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]
}

193
vendor/github.com/Sirupsen/logrus/exported.go generated vendored Normal file
View File

@@ -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.SetLevel(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...)
}

45
vendor/github.com/Sirupsen/logrus/formatter.go generated vendored Normal file
View File

@@ -0,0 +1,45 @@
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) {
if t, ok := data["time"]; ok {
data["fields.time"] = t
}
if m, ok := data["msg"]; ok {
data["fields.msg"] = m
}
if l, ok := data["level"]; ok {
data["fields.level"] = l
}
}

34
vendor/github.com/Sirupsen/logrus/hooks.go generated vendored Normal file
View File

@@ -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
}

79
vendor/github.com/Sirupsen/logrus/json_formatter.go generated vendored Normal file
View File

@@ -0,0 +1,79 @@
package logrus
import (
"encoding/json"
"fmt"
)
type fieldKey string
// FieldMap allows customization of the key names for default fields.
type FieldMap map[fieldKey]string
// Default key names for the default fields
const (
FieldKeyMsg = "msg"
FieldKeyLevel = "level"
FieldKeyTime = "time"
)
func (f FieldMap) resolve(key fieldKey) string {
if k, ok := f[key]; ok {
return k
}
return string(key)
}
// JSONFormatter formats logs into parsable json
type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string
// DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool
// FieldMap allows users to customize the names of keys for default fields.
// As an example:
// formatter := &JSONFormatter{
// FieldMap: FieldMap{
// FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level",
// FieldKeyMsg: "@message",
// },
// }
FieldMap FieldMap
}
// Format renders a single log entry
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
}
if !f.DisableTimestamp {
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
}
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
data[f.FieldMap.resolve(FieldKeyLevel)] = 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
}

323
vendor/github.com/Sirupsen/logrus/logger.go generated vendored Normal file
View File

@@ -0,0 +1,323 @@
package logrus
import (
"io"
"os"
"sync"
"sync/atomic"
)
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.
Level Level
// Used to sync writing to the log. Locking is enabled by Default
mu MutexWrap
// Reusable empty entry
entryPool sync.Pool
}
type MutexWrap struct {
lock sync.Mutex
disabled bool
}
func (mw *MutexWrap) Lock() {
if !mw.disabled {
mw.lock.Lock()
}
}
func (mw *MutexWrap) Unlock() {
if !mw.disabled {
mw.lock.Unlock()
}
}
func (mw *MutexWrap) Disable() {
mw.disabled = true
}
// 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,
}
}
func (logger *Logger) newEntry() *Entry {
entry, ok := logger.entryPool.Get().(*Entry)
if ok {
return entry
}
return NewEntry(logger)
}
func (logger *Logger) releaseEntry(entry *Entry) {
logger.entryPool.Put(entry)
}
// Adds a field to the log entry, note that 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 {
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.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 {
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.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 {
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithError(err)
}
func (logger *Logger) Debugf(format string, args ...interface{}) {
if logger.level() >= DebugLevel {
entry := logger.newEntry()
entry.Debugf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Infof(format string, args ...interface{}) {
if logger.level() >= InfoLevel {
entry := logger.newEntry()
entry.Infof(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Printf(format string, args ...interface{}) {
entry := logger.newEntry()
entry.Printf(format, args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warnf(format string, args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warningf(format string, args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Errorf(format string, args ...interface{}) {
if logger.level() >= ErrorLevel {
entry := logger.newEntry()
entry.Errorf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatalf(format string, args ...interface{}) {
if logger.level() >= FatalLevel {
entry := logger.newEntry()
entry.Fatalf(format, args...)
logger.releaseEntry(entry)
}
Exit(1)
}
func (logger *Logger) Panicf(format string, args ...interface{}) {
if logger.level() >= PanicLevel {
entry := logger.newEntry()
entry.Panicf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Debug(args ...interface{}) {
if logger.level() >= DebugLevel {
entry := logger.newEntry()
entry.Debug(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Info(args ...interface{}) {
if logger.level() >= InfoLevel {
entry := logger.newEntry()
entry.Info(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Print(args ...interface{}) {
entry := logger.newEntry()
entry.Info(args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warn(args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warning(args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Error(args ...interface{}) {
if logger.level() >= ErrorLevel {
entry := logger.newEntry()
entry.Error(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatal(args ...interface{}) {
if logger.level() >= FatalLevel {
entry := logger.newEntry()
entry.Fatal(args...)
logger.releaseEntry(entry)
}
Exit(1)
}
func (logger *Logger) Panic(args ...interface{}) {
if logger.level() >= PanicLevel {
entry := logger.newEntry()
entry.Panic(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Debugln(args ...interface{}) {
if logger.level() >= DebugLevel {
entry := logger.newEntry()
entry.Debugln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Infoln(args ...interface{}) {
if logger.level() >= InfoLevel {
entry := logger.newEntry()
entry.Infoln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Println(args ...interface{}) {
entry := logger.newEntry()
entry.Println(args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warnln(args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warningln(args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Errorln(args ...interface{}) {
if logger.level() >= ErrorLevel {
entry := logger.newEntry()
entry.Errorln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatalln(args ...interface{}) {
if logger.level() >= FatalLevel {
entry := logger.newEntry()
entry.Fatalln(args...)
logger.releaseEntry(entry)
}
Exit(1)
}
func (logger *Logger) Panicln(args ...interface{}) {
if logger.level() >= PanicLevel {
entry := logger.newEntry()
entry.Panicln(args...)
logger.releaseEntry(entry)
}
}
//When file is opened with appending mode, it's safe to
//write concurrently to a file (within 4k message on Linux).
//In these cases user can choose to disable the lock.
func (logger *Logger) SetNoLock() {
logger.mu.Disable()
}
func (logger *Logger) level() Level {
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
}
func (logger *Logger) SetLevel(level Level) {
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
}
func (logger *Logger) AddHook(hook Hook) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Hooks.Add(hook)
}

143
vendor/github.com/Sirupsen/logrus/logrus.go generated vendored Normal file
View File

@@ -0,0 +1,143 @@
package logrus
import (
"fmt"
"log"
"strings"
)
// Fields type, used to pass to `WithFields`.
type Fields map[string]interface{}
// Level type
type Level uint32
// 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{})
}
// The FieldLogger interface generalizes the Entry and Logger types
type FieldLogger interface {
WithField(key string, value interface{}) *Entry
WithFields(fields Fields) *Entry
WithError(err error) *Entry
Debugf(format string, args ...interface{})
Infof(format string, args ...interface{})
Printf(format string, args ...interface{})
Warnf(format string, args ...interface{})
Warningf(format string, args ...interface{})
Errorf(format string, args ...interface{})
Fatalf(format string, args ...interface{})
Panicf(format string, args ...interface{})
Debug(args ...interface{})
Info(args ...interface{})
Print(args ...interface{})
Warn(args ...interface{})
Warning(args ...interface{})
Error(args ...interface{})
Fatal(args ...interface{})
Panic(args ...interface{})
Debugln(args ...interface{})
Infoln(args ...interface{})
Println(args ...interface{})
Warnln(args ...interface{})
Warningln(args ...interface{})
Errorln(args ...interface{})
Fatalln(args ...interface{})
Panicln(args ...interface{})
}

10
vendor/github.com/Sirupsen/logrus/terminal_bsd.go generated vendored Normal file
View File

@@ -0,0 +1,10 @@
// +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine,!gopherjs
package logrus
import "golang.org/x/sys/unix"
const ioctlReadTermios = unix.TIOCGETA
type Termios unix.Termios

View File

@@ -0,0 +1,11 @@
// +build appengine gopherjs
package logrus
import (
"io"
)
func checkIfTerminal(w io.Writer) bool {
return true
}

View File

@@ -0,0 +1,19 @@
// +build !appengine,!gopherjs
package logrus
import (
"io"
"os"
"golang.org/x/crypto/ssh/terminal"
)
func checkIfTerminal(w io.Writer) bool {
switch v := w.(type) {
case *os.File:
return terminal.IsTerminal(int(v.Fd()))
default:
return false
}
}

14
vendor/github.com/Sirupsen/logrus/terminal_linux.go generated vendored Normal file
View File

@@ -0,0 +1,14 @@
// 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.
// +build !appengine,!gopherjs
package logrus
import "golang.org/x/sys/unix"
const ioctlReadTermios = unix.TCGETS
type Termios unix.Termios

178
vendor/github.com/Sirupsen/logrus/text_formatter.go generated vendored Normal file
View File

@@ -0,0 +1,178 @@
package logrus
import (
"bytes"
"fmt"
"sort"
"strings"
"sync"
"time"
)
const (
nocolor = 0
red = 31
green = 32
yellow = 33
blue = 36
gray = 37
)
var (
baseTimestamp time.Time
)
func init() {
baseTimestamp = time.Now()
}
// TextFormatter formats logs into text
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
// QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool
// Whether the logger's out is to a terminal
isTerminal bool
sync.Once
}
func (f *TextFormatter) init(entry *Entry) {
if entry.Logger != nil {
f.isTerminal = checkIfTerminal(entry.Logger.Out)
}
}
// Format renders a single log entry
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var b *bytes.Buffer
keys := make([]string, 0, len(entry.Data))
for k := range entry.Data {
keys = append(keys, k)
}
if !f.DisableSorting {
sort.Strings(keys)
}
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
prefixFieldClashes(entry.Data)
f.Do(func() { f.init(entry) })
isColored := (f.ForceColors || f.isTerminal) && !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.DisableTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
} else if !f.FullTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), 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=", levelColor, k)
f.appendValue(b, v)
}
}
func (f *TextFormatter) needsQuoting(text string) bool {
if f.QuoteEmptyFields && len(text) == 0 {
return true
}
for _, ch := range text {
if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') ||
ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') {
return true
}
}
return false
}
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
if b.Len() > 0 {
b.WriteByte(' ')
}
b.WriteString(key)
b.WriteByte('=')
f.appendValue(b, value)
}
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
stringVal, ok := value.(string)
if !ok {
stringVal = fmt.Sprint(value)
}
if !f.needsQuoting(stringVal) {
b.WriteString(stringVal)
} else {
b.WriteString(fmt.Sprintf("%q", stringVal))
}
}

62
vendor/github.com/Sirupsen/logrus/writer.go generated vendored Normal file
View File

@@ -0,0 +1,62 @@
package logrus
import (
"bufio"
"io"
"runtime"
)
func (logger *Logger) Writer() *io.PipeWriter {
return logger.WriterLevel(InfoLevel)
}
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
return NewEntry(logger).WriterLevel(level)
}
func (entry *Entry) Writer() *io.PipeWriter {
return entry.WriterLevel(InfoLevel)
}
func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
reader, writer := io.Pipe()
var printFunc func(args ...interface{})
switch level {
case DebugLevel:
printFunc = entry.Debug
case InfoLevel:
printFunc = entry.Info
case WarnLevel:
printFunc = entry.Warn
case ErrorLevel:
printFunc = entry.Error
case FatalLevel:
printFunc = entry.Fatal
case PanicLevel:
printFunc = entry.Panic
default:
printFunc = entry.Print
}
go entry.writerScanner(reader, printFunc)
runtime.SetFinalizer(writer, writerFinalizer)
return writer
}
func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
printFunc(scanner.Text())
}
if err := scanner.Err(); err != nil {
entry.Errorf("Error while reading from Writer: %s", err)
}
reader.Close()
}
func writerFinalizer(writer *io.PipeWriter) {
writer.Close()
}

File diff suppressed because it is too large Load Diff

View File

@@ -10,17 +10,17 @@ It consists of various components in this repository:
- `client/` The Go client used by the command-line client. It can also be used by third-party Go programs. - `client/` The Go client used by the command-line client. It can also be used by third-party Go programs.
- `daemon/` The daemon, which serves the API. - `daemon/` The daemon, which serves the API.
## Swagger definition ## Swagger definition
The API is defined by the [Swagger](http://swagger.io/specification/) definition in `api/swagger.yaml`. This definition can be used to: The API is defined by the [Swagger](http://swagger.io/specification/) definition in `api/swagger.yaml`. This definition can be used to:
1. Automatically generate documentation. 1. To automatically generate documentation.
2. Automatically generate the Go server and client. (A work-in-progress.) 2. To automatically generate the Go server and client. (A work-in-progress.)
3. Provide a machine readable version of the API for introspecting what it can do, automatically generating clients for other languages, etc. 3. Provide a machine readable version of the API for introspecting what it can do, automatically generating clients for other languages, etc.
## Updating the API documentation ## Updating the API documentation
The API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, edit this file to represent the change in the documentation. The API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, you'll need to edit this file to represent the change in the documentation.
The file is split into two main sections: The file is split into two main sections:
@@ -29,9 +29,9 @@ The file is split into two main sections:
To make an edit, first look for the endpoint you want to edit under `paths`, then make the required edits. Endpoints may reference reusable objects with `$ref`, which can be found in the `definitions` section. To make an edit, first look for the endpoint you want to edit under `paths`, then make the required edits. Endpoints may reference reusable objects with `$ref`, which can be found in the `definitions` section.
There is hopefully enough example material in the file for you to copy a similar pattern from elsewhere in the file (e.g. adding new fields or endpoints), but for the full reference, see the [Swagger specification](https://github.com/docker/docker/issues/27919). There is hopefully enough example material in the file for you to copy a similar pattern from elsewhere in the file (e.g. adding new fields or endpoints), but for the full reference, see the [Swagger specification](https://github.com/docker/docker/issues/27919)
`swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful when making edits to ensure you are doing the right thing. `swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful for when you are making edits to ensure you are doing the right thing.
## Viewing the API documentation ## Viewing the API documentation

View File

@@ -1,11 +1,166 @@
package api // import "github.com/docker/docker/api" package api
import (
"encoding/json"
"encoding/pem"
"fmt"
"mime"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/system"
"github.com/docker/libtrust"
)
// Common constants for daemon and client. // Common constants for daemon and client.
const ( const (
// DefaultVersion of Current REST API // DefaultVersion of Current REST API
DefaultVersion = "1.38" DefaultVersion string = "1.29"
// NoBaseImageSpecifier is the symbol used by the FROM // NoBaseImageSpecifier is the symbol used by the FROM
// command to specify that no base image is to be used. // command to specify that no base image is to be used.
NoBaseImageSpecifier = "scratch" NoBaseImageSpecifier string = "scratch"
) )
// byPortInfo is a temporary type used to sort types.Port by its fields
type byPortInfo []types.Port
func (r byPortInfo) Len() int { return len(r) }
func (r byPortInfo) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
func (r byPortInfo) Less(i, j int) bool {
if r[i].PrivatePort != r[j].PrivatePort {
return r[i].PrivatePort < r[j].PrivatePort
}
if r[i].IP != r[j].IP {
return r[i].IP < r[j].IP
}
if r[i].PublicPort != r[j].PublicPort {
return r[i].PublicPort < r[j].PublicPort
}
return r[i].Type < r[j].Type
}
// DisplayablePorts returns formatted string representing open ports of container
// e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
// it's used by command 'docker ps'
func DisplayablePorts(ports []types.Port) string {
type portGroup struct {
first uint16
last uint16
}
groupMap := make(map[string]*portGroup)
var result []string
var hostMappings []string
var groupMapKeys []string
sort.Sort(byPortInfo(ports))
for _, port := range ports {
current := port.PrivatePort
portKey := port.Type
if port.IP != "" {
if port.PublicPort != current {
hostMappings = append(hostMappings, fmt.Sprintf("%s:%d->%d/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type))
continue
}
portKey = fmt.Sprintf("%s/%s", port.IP, port.Type)
}
group := groupMap[portKey]
if group == nil {
groupMap[portKey] = &portGroup{first: current, last: current}
// record order that groupMap keys are created
groupMapKeys = append(groupMapKeys, portKey)
continue
}
if current == (group.last + 1) {
group.last = current
continue
}
result = append(result, formGroup(portKey, group.first, group.last))
groupMap[portKey] = &portGroup{first: current, last: current}
}
for _, portKey := range groupMapKeys {
g := groupMap[portKey]
result = append(result, formGroup(portKey, g.first, g.last))
}
result = append(result, hostMappings...)
return strings.Join(result, ", ")
}
func formGroup(key string, start, last uint16) string {
parts := strings.Split(key, "/")
groupType := parts[0]
var ip string
if len(parts) > 1 {
ip = parts[0]
groupType = parts[1]
}
group := strconv.Itoa(int(start))
if start != last {
group = fmt.Sprintf("%s-%d", group, last)
}
if ip != "" {
group = fmt.Sprintf("%s:%s->%s", ip, group, group)
}
return fmt.Sprintf("%s/%s", group, groupType)
}
// MatchesContentType validates the content type against the expected one
func MatchesContentType(contentType, expectedType string) bool {
mimetype, _, err := mime.ParseMediaType(contentType)
if err != nil {
logrus.Errorf("Error parsing media type: %s error: %v", contentType, err)
}
return err == nil && mimetype == expectedType
}
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
// otherwise generates a new one
func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700)
if err != nil {
return nil, err
}
trustKey, err := libtrust.LoadKeyFile(trustKeyPath)
if err == libtrust.ErrKeyFileDoesNotExist {
trustKey, err = libtrust.GenerateECP256PrivateKey()
if err != nil {
return nil, fmt.Errorf("Error generating key: %s", err)
}
encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath))
if err != nil {
return nil, fmt.Errorf("Error serializing key: %s", err)
}
if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil {
return nil, fmt.Errorf("Error saving key file: %s", err)
}
} else if err != nil {
return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err)
}
return trustKey, nil
}
func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) {
if ext == ".json" || ext == ".jwk" {
encoded, err = json.Marshal(key)
if err != nil {
return nil, fmt.Errorf("unable to encode private key JWK: %s", err)
}
} else {
pemBlock, err := key.PEMBlock()
if err != nil {
return nil, fmt.Errorf("unable to encode private key PEM: %s", err)
}
encoded = pem.EncodeToMemory(pemBlock)
}
return
}

View File

@@ -1,6 +1,6 @@
// +build !windows // +build !windows
package api // import "github.com/docker/docker/api" package api
// MinVersion represents Minimum REST API version supported // MinVersion represents Minimum REST API version supported
const MinVersion = "1.12" const MinVersion string = "1.12"

View File

@@ -1,4 +1,4 @@
package api // import "github.com/docker/docker/api" package api
// MinVersion represents Minimum REST API version supported // MinVersion represents Minimum REST API version supported
// Technically the first daemon API version released on Windows is v1.25 in // Technically the first daemon API version released on Windows is v1.25 in

9
vendor/github.com/docker/docker/api/names.go generated vendored Normal file
View File

@@ -0,0 +1,9 @@
package api
import "regexp"
// RestrictedNameChars collects the characters allowed to represent a name, normally used to validate container and volume names.
const RestrictedNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]`
// RestrictedNamePattern is a regular expression to validate names against the collection of restricted characters.
var RestrictedNamePattern = regexp.MustCompile(`^` + RestrictedNameChars + `+$`)

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
package types // import "github.com/docker/docker/api/types" package types
// AuthConfig contains authorization information for connecting to a Registry // AuthConfig contains authorization information for connecting to a Registry
type AuthConfig struct { type AuthConfig struct {

View File

@@ -1,4 +1,4 @@
package blkiodev // import "github.com/docker/docker/api/types/blkiodev" package blkiodev
import "fmt" import "fmt"

View File

@@ -1,4 +1,4 @@
package types // import "github.com/docker/docker/api/types" package types
import ( import (
"bufio" "bufio"
@@ -74,7 +74,6 @@ type ContainerLogsOptions struct {
ShowStdout bool ShowStdout bool
ShowStderr bool ShowStderr bool
Since string Since string
Until string
Timestamps bool Timestamps bool
Follow bool Follow bool
Tail string Tail string
@@ -98,7 +97,6 @@ type ContainerStartOptions struct {
// about files to copy into a container // about files to copy into a container
type CopyToContainerOptions struct { type CopyToContainerOptions struct {
AllowOverwriteDirWithFile bool AllowOverwriteDirWithFile bool
CopyUIDGID bool
} }
// EventsOptions holds parameters to filter events with. // EventsOptions holds parameters to filter events with.
@@ -179,26 +177,8 @@ type ImageBuildOptions struct {
SecurityOpt []string SecurityOpt []string
ExtraHosts []string // List of extra hosts ExtraHosts []string // List of extra hosts
Target string Target string
SessionID string
Platform string
// Version specifies the version of the unerlying builder to use
Version BuilderVersion
// BuildID is an optional identifier that can be passed together with the
// build request. The same identifier can be used to gracefully cancel the
// build with the cancel request.
BuildID string
} }
// BuilderVersion sets the version of underlying builder to use
type BuilderVersion string
const (
// BuilderV1 is the first generation builder in docker daemon
BuilderV1 BuilderVersion = "1"
// BuilderBuildKit is builder based on moby/buildkit project
BuilderBuildKit = "2"
)
// ImageBuildResponse holds information // ImageBuildResponse holds information
// returned by a server after building // returned by a server after building
// an image. // an image.
@@ -209,8 +189,7 @@ type ImageBuildResponse struct {
// ImageCreateOptions holds information to create images. // ImageCreateOptions holds information to create images.
type ImageCreateOptions struct { type ImageCreateOptions struct {
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry. RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
Platform string // Platform is the target platform of the image if it needs to be pulled from the registry.
} }
// ImageImportSource holds source information for ImageImport // ImageImportSource holds source information for ImageImport
@@ -224,7 +203,6 @@ type ImageImportOptions struct {
Tag string // Tag is the name to tag this image with. This attribute is deprecated. Tag string // Tag is the name to tag this image with. This attribute is deprecated.
Message string // Message is the message to tag the image with Message string // Message is the message to tag the image with
Changes []string // Changes are the raw changes to apply to this image Changes []string // Changes are the raw changes to apply to this image
Platform string // Platform is the target platform of the image
} }
// ImageListOptions holds parameters to filter the list of images with. // ImageListOptions holds parameters to filter the list of images with.
@@ -245,7 +223,6 @@ type ImagePullOptions struct {
All bool All bool
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
PrivilegeFunc RequestPrivilegeFunc PrivilegeFunc RequestPrivilegeFunc
Platform string
} }
// RequestPrivilegeFunc is a function interface that // RequestPrivilegeFunc is a function interface that
@@ -298,12 +275,6 @@ type ServiceCreateOptions struct {
// //
// This field follows the format of the X-Registry-Auth header. // This field follows the format of the X-Registry-Auth header.
EncodedRegistryAuth string EncodedRegistryAuth string
// QueryRegistry indicates whether the service update requires
// contacting a registry. A registry may be contacted to retrieve
// the image digest and manifest, which in turn can be used to update
// platform or other information about the service.
QueryRegistry bool
} }
// ServiceCreateResponse contains the information returned to a client // ServiceCreateResponse contains the information returned to a client
@@ -343,12 +314,6 @@ type ServiceUpdateOptions struct {
// The valid values are "previous" and "none". An empty value is the // The valid values are "previous" and "none". An empty value is the
// same as "none". // same as "none".
Rollback string Rollback string
// QueryRegistry indicates whether the service update requires
// contacting a registry. A registry may be contacted to retrieve
// the image digest and manifest, which in turn can be used to update
// platform or other information about the service.
QueryRegistry bool
} }
// ServiceListOptions holds parameters to list services with. // ServiceListOptions holds parameters to list services with.

View File

@@ -1,4 +1,4 @@
package types // import "github.com/docker/docker/api/types" package types
import ( import (
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
@@ -25,6 +25,19 @@ type ContainerRmConfig struct {
ForceRemove, RemoveVolume, RemoveLink bool ForceRemove, RemoveVolume, RemoveLink bool
} }
// ContainerCommitConfig contains build configs for commit operation,
// and is used when making a commit with the current state of the container.
type ContainerCommitConfig struct {
Pause bool
Repo string
Tag string
Author string
Comment string
// merge container config into commit config before commit
MergeConfigs bool
Config *container.Config
}
// ExecConfig is a small subset of the Config struct that holds the configuration // ExecConfig is a small subset of the Config struct that holds the configuration
// for the exec feature of docker. // for the exec feature of docker.
type ExecConfig struct { type ExecConfig struct {
@@ -37,7 +50,6 @@ type ExecConfig struct {
Detach bool // Execute in detach mode Detach bool // Execute in detach mode
DetachKeys string // Escape keys for detach DetachKeys string // Escape keys for detach
Env []string // Environment variables Env []string // Environment variables
WorkingDir string // Working directory
Cmd []string // Execution commands and args Cmd []string // Execution commands and args
} }

View File

@@ -1,4 +1,4 @@
package container // import "github.com/docker/docker/api/types/container" package container
import ( import (
"time" "time"
@@ -7,12 +7,6 @@ import (
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
) )
// MinimumDuration puts a minimum on user configured duration.
// This is to prevent API error on time unit. For example, API may
// set 3 as healthcheck interval with intention of 3 seconds, but
// Docker interprets it as 3 nanoseconds.
const MinimumDuration = 1 * time.Millisecond
// HealthConfig holds configuration settings for the HEALTHCHECK feature. // HealthConfig holds configuration settings for the HEALTHCHECK feature.
type HealthConfig struct { type HealthConfig struct {
// Test is the test to perform to check that the container is healthy. // Test is the test to perform to check that the container is healthy.

View File

@@ -7,7 +7,7 @@ package container
// See hack/generate-swagger-api.sh // See hack/generate-swagger-api.sh
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ContainerChangeResponseItem change item in response to ContainerChanges operation // ContainerChangeResponseItem container change response item
// swagger:model ContainerChangeResponseItem // swagger:model ContainerChangeResponseItem
type ContainerChangeResponseItem struct { type ContainerChangeResponseItem struct {

View File

@@ -7,7 +7,7 @@ package container
// See hack/generate-swagger-api.sh // See hack/generate-swagger-api.sh
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ContainerCreateCreatedBody OK response to ContainerCreate operation // ContainerCreateCreatedBody container create created body
// swagger:model ContainerCreateCreatedBody // swagger:model ContainerCreateCreatedBody
type ContainerCreateCreatedBody struct { type ContainerCreateCreatedBody struct {

View File

@@ -7,7 +7,7 @@ package container
// See hack/generate-swagger-api.sh // See hack/generate-swagger-api.sh
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ContainerTopOKBody OK response to ContainerTop operation // ContainerTopOKBody container top o k body
// swagger:model ContainerTopOKBody // swagger:model ContainerTopOKBody
type ContainerTopOKBody struct { type ContainerTopOKBody struct {

View File

@@ -7,7 +7,7 @@ package container
// See hack/generate-swagger-api.sh // See hack/generate-swagger-api.sh
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ContainerUpdateOKBody OK response to ContainerUpdate operation // ContainerUpdateOKBody container update o k body
// swagger:model ContainerUpdateOKBody // swagger:model ContainerUpdateOKBody
type ContainerUpdateOKBody struct { type ContainerUpdateOKBody struct {

View File

@@ -7,22 +7,10 @@ package container
// See hack/generate-swagger-api.sh // See hack/generate-swagger-api.sh
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ContainerWaitOKBodyError container waiting error, if any // ContainerWaitOKBody container wait o k body
// swagger:model ContainerWaitOKBodyError
type ContainerWaitOKBodyError struct {
// Details of an error
Message string `json:"Message,omitempty"`
}
// ContainerWaitOKBody OK response to ContainerWait operation
// swagger:model ContainerWaitOKBody // swagger:model ContainerWaitOKBody
type ContainerWaitOKBody struct { type ContainerWaitOKBody struct {
// error
// Required: true
Error *ContainerWaitOKBodyError `json:"Error"`
// Exit code of the container // Exit code of the container
// Required: true // Required: true
StatusCode int64 `json:"StatusCode"` StatusCode int64 `json:"StatusCode"`

View File

@@ -1,4 +1,4 @@
package container // import "github.com/docker/docker/api/types/container" package container
import ( import (
"strings" "strings"
@@ -20,70 +20,44 @@ func (i Isolation) IsDefault() bool {
return strings.ToLower(string(i)) == "default" || string(i) == "" return strings.ToLower(string(i)) == "default" || string(i) == ""
} }
// IsHyperV indicates the use of a Hyper-V partition for isolation
func (i Isolation) IsHyperV() bool {
return strings.ToLower(string(i)) == "hyperv"
}
// IsProcess indicates the use of process isolation
func (i Isolation) IsProcess() bool {
return strings.ToLower(string(i)) == "process"
}
const (
// IsolationEmpty is unspecified (same behavior as default)
IsolationEmpty = Isolation("")
// IsolationDefault is the default isolation mode on current daemon
IsolationDefault = Isolation("default")
// IsolationProcess is process isolation mode
IsolationProcess = Isolation("process")
// IsolationHyperV is HyperV isolation mode
IsolationHyperV = Isolation("hyperv")
)
// IpcMode represents the container ipc stack. // IpcMode represents the container ipc stack.
type IpcMode string type IpcMode string
// IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared. // IsPrivate indicates whether the container uses its private ipc stack.
func (n IpcMode) IsPrivate() bool { func (n IpcMode) IsPrivate() bool {
return n == "private" return !(n.IsHost() || n.IsContainer())
} }
// IsHost indicates whether the container shares the host's ipc namespace. // IsHost indicates whether the container uses the host's ipc stack.
func (n IpcMode) IsHost() bool { func (n IpcMode) IsHost() bool {
return n == "host" return n == "host"
} }
// IsShareable indicates whether the container's ipc namespace can be shared with another container. // IsContainer indicates whether the container uses a container's ipc stack.
func (n IpcMode) IsShareable() bool {
return n == "shareable"
}
// IsContainer indicates whether the container uses another container's ipc namespace.
func (n IpcMode) IsContainer() bool { func (n IpcMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2) parts := strings.SplitN(string(n), ":", 2)
return len(parts) > 1 && parts[0] == "container" return len(parts) > 1 && parts[0] == "container"
} }
// IsNone indicates whether container IpcMode is set to "none". // Valid indicates whether the ipc stack is valid.
func (n IpcMode) IsNone() bool {
return n == "none"
}
// IsEmpty indicates whether container IpcMode is empty
func (n IpcMode) IsEmpty() bool {
return n == ""
}
// Valid indicates whether the ipc mode is valid.
func (n IpcMode) Valid() bool { func (n IpcMode) Valid() bool {
return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer() parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
case "", "host":
case "container":
if len(parts) != 2 || parts[1] == "" {
return false
}
default:
return false
}
return true
} }
// Container returns the name of the container ipc stack is going to be used. // Container returns the name of the container ipc stack is going to be used.
func (n IpcMode) Container() string { func (n IpcMode) Container() string {
parts := strings.SplitN(string(n), ":", 2) parts := strings.SplitN(string(n), ":", 2)
if len(parts) > 1 && parts[0] == "container" { if len(parts) > 1 {
return parts[1] return parts[1]
} }
return "" return ""
@@ -401,12 +375,6 @@ type HostConfig struct {
// Mounts specs used by the container // Mounts specs used by the container
Mounts []mount.Mount `json:",omitempty"` Mounts []mount.Mount `json:",omitempty"`
// MaskedPaths is the list of paths to be masked inside the container (this overrides the default set of paths)
MaskedPaths []string
// ReadonlyPaths is the list of paths to be set as read-only inside the container (this overrides the default set of paths)
ReadonlyPaths []string
// Run a custom init inside the container, if null, use the daemon's configured settings // Run a custom init inside the container, if null, use the daemon's configured settings
Init *bool `json:",omitempty"` Init *bool `json:",omitempty"`
} }

View File

@@ -1,6 +1,6 @@
// +build !windows // +build !windows
package container // import "github.com/docker/docker/api/types/container" package container
// IsValid indicates if an isolation technology is valid // IsValid indicates if an isolation technology is valid
func (i Isolation) IsValid() bool { func (i Isolation) IsValid() bool {

View File

@@ -1,4 +1,8 @@
package container // import "github.com/docker/docker/api/types/container" package container
import (
"strings"
)
// IsBridge indicates whether container uses the bridge network stack // IsBridge indicates whether container uses the bridge network stack
// in windows it is given the name NAT // in windows it is given the name NAT
@@ -17,6 +21,16 @@ func (n NetworkMode) IsUserDefined() bool {
return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer() return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer()
} }
// IsHyperV indicates the use of a Hyper-V partition for isolation
func (i Isolation) IsHyperV() bool {
return strings.ToLower(string(i)) == "hyperv"
}
// IsProcess indicates the use of process isolation
func (i Isolation) IsProcess() bool {
return strings.ToLower(string(i)) == "process"
}
// IsValid indicates if an isolation technology is valid // IsValid indicates if an isolation technology is valid
func (i Isolation) IsValid() bool { func (i Isolation) IsValid() bool {
return i.IsDefault() || i.IsHyperV() || i.IsProcess() return i.IsDefault() || i.IsHyperV() || i.IsProcess()

View File

@@ -1,22 +0,0 @@
package container // import "github.com/docker/docker/api/types/container"
// WaitCondition is a type used to specify a container state for which
// to wait.
type WaitCondition string
// Possible WaitCondition Values.
//
// WaitConditionNotRunning (default) is used to wait for any of the non-running
// states: "created", "exited", "dead", "removing", or "removed".
//
// WaitConditionNextExit is used to wait for the next time the state changes
// to a non-running state. If the state is currently "created" or "exited",
// this would cause Wait() to block until either the container runs and exits
// or is removed.
//
// WaitConditionRemoved is used to wait for the container to be removed.
const (
WaitConditionNotRunning WaitCondition = "not-running"
WaitConditionNextExit WaitCondition = "next-exit"
WaitConditionRemoved WaitCondition = "removed"
)

View File

@@ -1,4 +1,4 @@
package events // import "github.com/docker/docker/api/types/events" package events
const ( const (
// ContainerEventType is the event type that containers generate // ContainerEventType is the event type that containers generate
@@ -13,14 +13,6 @@ const (
PluginEventType = "plugin" PluginEventType = "plugin"
// VolumeEventType is the event type that volumes generate // VolumeEventType is the event type that volumes generate
VolumeEventType = "volume" VolumeEventType = "volume"
// ServiceEventType is the event type that services generate
ServiceEventType = "service"
// NodeEventType is the event type that nodes generate
NodeEventType = "node"
// SecretEventType is the event type that secrets generate
SecretEventType = "secret"
// ConfigEventType is the event type that configs generate
ConfigEventType = "config"
) )
// Actor describes something that generates events, // Actor describes something that generates events,
@@ -44,8 +36,6 @@ type Message struct {
Type string Type string
Action string Action string
Actor Actor Actor Actor
// Engine events are local scope. Cluster events are swarm scope.
Scope string `json:"scope,omitempty"`
Time int64 `json:"time,omitempty"` Time int64 `json:"time,omitempty"`
TimeNano int64 `json:"timeNano,omitempty"` TimeNano int64 `json:"timeNano,omitempty"`

View File

@@ -1,45 +1,38 @@
/*Package filters provides tools for encoding a mapping of keys to a set of // Package filters provides helper function to parse and handle command line
multiple values. // filter, used for example in docker ps or docker images commands.
*/ package filters
package filters // import "github.com/docker/docker/api/types/filters"
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"regexp" "regexp"
"strings" "strings"
"github.com/docker/docker/api/types/versions" "github.com/docker/docker/api/types/versions"
) )
// Args stores a mapping of keys to a set of multiple values. // Args stores filter arguments as map key:{map key: bool}.
// It contains an aggregation of the map of arguments (which are in the form
// of -f 'key=value') based on the key, and stores values for the same key
// in a map with string keys and boolean values.
// e.g given -f 'label=label1=1' -f 'label=label2=2' -f 'image.name=ubuntu'
// the args will be {"image.name":{"ubuntu":true},"label":{"label1=1":true,"label2=2":true}}
type Args struct { type Args struct {
fields map[string]map[string]bool fields map[string]map[string]bool
} }
// KeyValuePair are used to initialize a new Args // NewArgs initializes a new Args struct.
type KeyValuePair struct { func NewArgs() Args {
Key string return Args{fields: map[string]map[string]bool{}}
Value string
} }
// Arg creates a new KeyValuePair for initializing Args // ParseFlag parses the argument to the filter flag. Like
func Arg(key, value string) KeyValuePair {
return KeyValuePair{Key: key, Value: value}
}
// NewArgs returns a new Args populated with the initial args
func NewArgs(initialArgs ...KeyValuePair) Args {
args := Args{fields: map[string]map[string]bool{}}
for _, arg := range initialArgs {
args.Add(arg.Key, arg.Value)
}
return args
}
// ParseFlag parses a key=value string and adds it to an Args.
// //
// Deprecated: Use Args.Add() // `docker ps -f 'created=today' -f 'image.name=ubuntu*'`
//
// If prev map is provided, then it is appended to, and returned. By default a new
// map is created.
func ParseFlag(arg string, prev Args) (Args, error) { func ParseFlag(arg string, prev Args) (Args, error) {
filters := prev filters := prev
if len(arg) == 0 { if len(arg) == 0 {
@@ -60,95 +53,74 @@ func ParseFlag(arg string, prev Args) (Args, error) {
return filters, nil return filters, nil
} }
// ErrBadFormat is an error returned when a filter is not in the form key=value // ErrBadFormat is an error returned in case of bad format for a filter.
//
// Deprecated: this error will be removed in a future version
var ErrBadFormat = errors.New("bad format of filter (expected name=value)") var ErrBadFormat = errors.New("bad format of filter (expected name=value)")
// ToParam encodes the Args as args JSON encoded string // ToParam packs the Args into a string for easy transport from client to server.
//
// Deprecated: use ToJSON
func ToParam(a Args) (string, error) { func ToParam(a Args) (string, error) {
return ToJSON(a) // this way we don't URL encode {}, just empty space
}
// MarshalJSON returns a JSON byte representation of the Args
func (args Args) MarshalJSON() ([]byte, error) {
if len(args.fields) == 0 {
return []byte{}, nil
}
return json.Marshal(args.fields)
}
// ToJSON returns the Args as a JSON encoded string
func ToJSON(a Args) (string, error) {
if a.Len() == 0 { if a.Len() == 0 {
return "", nil return "", nil
} }
buf, err := json.Marshal(a)
return string(buf), err buf, err := json.Marshal(a.fields)
if err != nil {
return "", err
}
return string(buf), nil
} }
// ToParamWithVersion encodes Args as a JSON string. If version is less than 1.22 // ToParamWithVersion packs the Args into a string for easy transport from client to server.
// then the encoded format will use an older legacy format where the values are a // The generated string will depend on the specified version (corresponding to the API version).
// list of strings, instead of a set.
//
// Deprecated: Use ToJSON
func ToParamWithVersion(version string, a Args) (string, error) { func ToParamWithVersion(version string, a Args) (string, error) {
// this way we don't URL encode {}, just empty space
if a.Len() == 0 { if a.Len() == 0 {
return "", nil return "", nil
} }
// for daemons older than v1.10, filter must be of the form map[string][]string
var buf []byte
var err error
if version != "" && versions.LessThan(version, "1.22") { if version != "" && versions.LessThan(version, "1.22") {
buf, err := json.Marshal(convertArgsToSlice(a.fields)) buf, err = json.Marshal(convertArgsToSlice(a.fields))
return string(buf), err } else {
buf, err = json.Marshal(a.fields)
} }
if err != nil {
return ToJSON(a) return "", err
}
return string(buf), nil
} }
// FromParam decodes a JSON encoded string into Args // FromParam unpacks the filter Args.
//
// Deprecated: use FromJSON
func FromParam(p string) (Args, error) { func FromParam(p string) (Args, error) {
return FromJSON(p) if len(p) == 0 {
} return NewArgs(), nil
// FromJSON decodes a JSON encoded string into Args
func FromJSON(p string) (Args, error) {
args := NewArgs()
if p == "" {
return args, nil
} }
raw := []byte(p) r := strings.NewReader(p)
err := json.Unmarshal(raw, &args) d := json.NewDecoder(r)
if err == nil {
return args, nil
}
// Fallback to parsing arguments in the legacy slice format m := map[string]map[string]bool{}
if err := d.Decode(&m); err != nil {
r.Seek(0, 0)
// Allow parsing old arguments in slice format.
// Because other libraries might be sending them in this format.
deprecated := map[string][]string{} deprecated := map[string][]string{}
if legacyErr := json.Unmarshal(raw, &deprecated); legacyErr != nil { if deprecatedErr := d.Decode(&deprecated); deprecatedErr == nil {
return args, err m = deprecatedArgs(deprecated)
} else {
return NewArgs(), err
} }
}
args.fields = deprecatedArgs(deprecated) return Args{m}, nil
return args, nil
} }
// UnmarshalJSON populates the Args from JSON encode bytes // Get returns the list of values associates with a field.
func (args Args) UnmarshalJSON(raw []byte) error { // It returns a slice of strings to keep backwards compatibility with old code.
if len(raw) == 0 { func (filters Args) Get(field string) []string {
return nil values := filters.fields[field]
}
return json.Unmarshal(raw, &args.fields)
}
// Get returns the list of values associated with the key
func (args Args) Get(key string) []string {
values := args.fields[key]
if values == nil { if values == nil {
return make([]string, 0) return make([]string, 0)
} }
@@ -159,34 +131,37 @@ func (args Args) Get(key string) []string {
return slice return slice
} }
// Add a new value to the set of values // Add adds a new value to a filter field.
func (args Args) Add(key, value string) { func (filters Args) Add(name, value string) {
if _, ok := args.fields[key]; ok { if _, ok := filters.fields[name]; ok {
args.fields[key][value] = true filters.fields[name][value] = true
} else { } else {
args.fields[key] = map[string]bool{value: true} filters.fields[name] = map[string]bool{value: true}
} }
} }
// Del removes a value from the set // Del removes a value from a filter field.
func (args Args) Del(key, value string) { func (filters Args) Del(name, value string) {
if _, ok := args.fields[key]; ok { if _, ok := filters.fields[name]; ok {
delete(args.fields[key], value) delete(filters.fields[name], value)
if len(args.fields[key]) == 0 { if len(filters.fields[name]) == 0 {
delete(args.fields, key) delete(filters.fields, name)
} }
} }
} }
// Len returns the number of keys in the mapping // Len returns the number of fields in the arguments.
func (args Args) Len() int { func (filters Args) Len() int {
return len(args.fields) return len(filters.fields)
} }
// MatchKVList returns true if all the pairs in sources exist as key=value // MatchKVList returns true if the values for the specified field matches the ones
// pairs in the mapping at key, or if there are no values at key. // from the sources.
func (args Args) MatchKVList(key string, sources map[string]string) bool { // e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}},
fieldValues := args.fields[key] // field is 'label' and sources are {'label1': '1', 'label2': '2'}
// it returns true.
func (filters Args) MatchKVList(field string, sources map[string]string) bool {
fieldValues := filters.fields[field]
//do not filter if there is no filter set or cannot determine filter //do not filter if there is no filter set or cannot determine filter
if len(fieldValues) == 0 { if len(fieldValues) == 0 {
@@ -197,8 +172,8 @@ func (args Args) MatchKVList(key string, sources map[string]string) bool {
return false return false
} }
for value := range fieldValues { for name2match := range fieldValues {
testKV := strings.SplitN(value, "=", 2) testKV := strings.SplitN(name2match, "=", 2)
v, ok := sources[testKV[0]] v, ok := sources[testKV[0]]
if !ok { if !ok {
@@ -212,13 +187,16 @@ func (args Args) MatchKVList(key string, sources map[string]string) bool {
return true return true
} }
// Match returns true if any of the values at key match the source string // Match returns true if the values for the specified field matches the source string
func (args Args) Match(field, source string) bool { // e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}},
if args.ExactMatch(field, source) { // field is 'image.name' and source is 'ubuntu'
// it returns true.
func (filters Args) Match(field, source string) bool {
if filters.ExactMatch(field, source) {
return true return true
} }
fieldValues := args.fields[field] fieldValues := filters.fields[field]
for name2match := range fieldValues { for name2match := range fieldValues {
match, err := regexp.MatchString(name2match, source) match, err := regexp.MatchString(name2match, source)
if err != nil { if err != nil {
@@ -231,9 +209,9 @@ func (args Args) Match(field, source string) bool {
return false return false
} }
// ExactMatch returns true if the source matches exactly one of the values. // ExactMatch returns true if the source matches exactly one of the filters.
func (args Args) ExactMatch(key, source string) bool { func (filters Args) ExactMatch(field, source string) bool {
fieldValues, ok := args.fields[key] fieldValues, ok := filters.fields[field]
//do not filter if there is no filter set or cannot determine filter //do not filter if there is no filter set or cannot determine filter
if !ok || len(fieldValues) == 0 { if !ok || len(fieldValues) == 0 {
return true return true
@@ -243,15 +221,14 @@ func (args Args) ExactMatch(key, source string) bool {
return fieldValues[source] return fieldValues[source]
} }
// UniqueExactMatch returns true if there is only one value and the source // UniqueExactMatch returns true if there is only one filter and the source matches exactly this one.
// matches exactly the value. func (filters Args) UniqueExactMatch(field, source string) bool {
func (args Args) UniqueExactMatch(key, source string) bool { fieldValues := filters.fields[field]
fieldValues := args.fields[key]
//do not filter if there is no filter set or cannot determine filter //do not filter if there is no filter set or cannot determine filter
if len(fieldValues) == 0 { if len(fieldValues) == 0 {
return true return true
} }
if len(args.fields[key]) != 1 { if len(filters.fields[field]) != 1 {
return false return false
} }
@@ -259,14 +236,14 @@ func (args Args) UniqueExactMatch(key, source string) bool {
return fieldValues[source] return fieldValues[source]
} }
// FuzzyMatch returns true if the source matches exactly one value, or the // FuzzyMatch returns true if the source matches exactly one of the filters,
// source has one of the values as a prefix. // or the source has one of the filters as a prefix.
func (args Args) FuzzyMatch(key, source string) bool { func (filters Args) FuzzyMatch(field, source string) bool {
if args.ExactMatch(key, source) { if filters.ExactMatch(field, source) {
return true return true
} }
fieldValues := args.fields[key] fieldValues := filters.fields[field]
for prefix := range fieldValues { for prefix := range fieldValues {
if strings.HasPrefix(source, prefix) { if strings.HasPrefix(source, prefix) {
return true return true
@@ -275,47 +252,30 @@ func (args Args) FuzzyMatch(key, source string) bool {
return false return false
} }
// Include returns true if the key exists in the mapping // Include returns true if the name of the field to filter is in the filters.
// func (filters Args) Include(field string) bool {
// Deprecated: use Contains _, ok := filters.fields[field]
func (args Args) Include(field string) bool {
_, ok := args.fields[field]
return ok return ok
} }
// Contains returns true if the key exists in the mapping // Validate ensures that all the fields in the filter are valid.
func (args Args) Contains(field string) bool { // It returns an error as soon as it finds an invalid field.
_, ok := args.fields[field] func (filters Args) Validate(accepted map[string]bool) error {
return ok for name := range filters.fields {
}
type invalidFilter string
func (e invalidFilter) Error() string {
return "Invalid filter '" + string(e) + "'"
}
func (invalidFilter) InvalidParameter() {}
// Validate compared the set of accepted keys against the keys in the mapping.
// An error is returned if any mapping keys are not in the accepted set.
func (args Args) Validate(accepted map[string]bool) error {
for name := range args.fields {
if !accepted[name] { if !accepted[name] {
return invalidFilter(name) return fmt.Errorf("Invalid filter '%s'", name)
} }
} }
return nil return nil
} }
// WalkValues iterates over the list of values for a key in the mapping and calls // WalkValues iterates over the list of filtered values for a field.
// op() for each value. If op returns an error the iteration stops and the // It stops the iteration if it finds an error and it returns that error.
// error is returned. func (filters Args) WalkValues(field string, op func(value string) error) error {
func (args Args) WalkValues(field string, op func(value string) error) error { if _, ok := filters.fields[field]; !ok {
if _, ok := args.fields[field]; !ok {
return nil return nil
} }
for v := range args.fields[field] { for v := range filters.fields[field] {
if err := op(v); err != nil { if err := op(v); err != nil {
return err return err
} }

View File

@@ -7,7 +7,7 @@ package image
// See hack/generate-swagger-api.sh // See hack/generate-swagger-api.sh
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// HistoryResponseItem individual image layer information in response to ImageHistory operation // HistoryResponseItem history response item
// swagger:model HistoryResponseItem // swagger:model HistoryResponseItem
type HistoryResponseItem struct { type HistoryResponseItem struct {

View File

@@ -1,4 +1,4 @@
package mount // import "github.com/docker/docker/api/types/mount" package mount
import ( import (
"os" "os"
@@ -15,8 +15,6 @@ const (
TypeVolume Type = "volume" TypeVolume Type = "volume"
// TypeTmpfs is the type for mounting tmpfs // TypeTmpfs is the type for mounting tmpfs
TypeTmpfs Type = "tmpfs" TypeTmpfs Type = "tmpfs"
// TypeNamedPipe is the type for mounting Windows named pipes
TypeNamedPipe Type = "npipe"
) )
// Mount represents a mount (volume). // Mount represents a mount (volume).
@@ -67,7 +65,7 @@ var Propagations = []Propagation{
type Consistency string type Consistency string
const ( const (
// ConsistencyFull guarantees bind mount-like consistency // ConsistencyFull guarantees bind-mount-like consistency
ConsistencyFull Consistency = "consistent" ConsistencyFull Consistency = "consistent"
// ConsistencyCached mounts can cache read data and FS structure // ConsistencyCached mounts can cache read data and FS structure
ConsistencyCached Consistency = "cached" ConsistencyCached Consistency = "cached"

View File

@@ -1,4 +1,4 @@
package network // import "github.com/docker/docker/api/types/network" package network
// Address represents an IP address // Address represents an IP address
type Address struct { type Address struct {
@@ -58,7 +58,6 @@ type EndpointSettings struct {
GlobalIPv6Address string GlobalIPv6Address string
GlobalIPv6PrefixLen int GlobalIPv6PrefixLen int
MacAddress string MacAddress string
DriverOpts map[string]string
} }
// Task carries the information about one backend task // Task carries the information about one backend task
@@ -101,8 +100,3 @@ func (es *EndpointSettings) Copy() *EndpointSettings {
type NetworkingConfig struct { type NetworkingConfig struct {
EndpointsConfig map[string]*EndpointSettings // Endpoint configs for each connecting network EndpointsConfig map[string]*EndpointSettings // Endpoint configs for each connecting network
} }
// ConfigReference specifies the source which provides a network's configuration
type ConfigReference struct {
Network string
}

View File

@@ -11,7 +11,7 @@ type Plugin struct {
// Required: true // Required: true
Config PluginConfig `json:"Config"` Config PluginConfig `json:"Config"`
// True if the plugin is running. False if the plugin is not running, only installed. // True when the plugin is running. False when the plugin is not running, only installed.
// Required: true // Required: true
Enabled bool `json:"Enabled"` Enabled bool `json:"Enabled"`
@@ -121,9 +121,6 @@ type PluginConfigArgs struct {
// swagger:model PluginConfigInterface // swagger:model PluginConfigInterface
type PluginConfigInterface struct { type PluginConfigInterface struct {
// Protocol to use for clients connecting to the plugin.
ProtocolScheme string `json:"ProtocolScheme,omitempty"`
// socket // socket
// Required: true // Required: true
Socket string `json:"Socket"` Socket string `json:"Socket"`

View File

@@ -1,4 +1,4 @@
package types // import "github.com/docker/docker/api/types" package types
import ( import (
"encoding/json" "encoding/json"
@@ -9,6 +9,14 @@ import (
// PluginsListResponse contains the response for the Engine API // PluginsListResponse contains the response for the Engine API
type PluginsListResponse []*Plugin type PluginsListResponse []*Plugin
const (
authzDriver = "AuthzDriver"
graphDriver = "GraphDriver"
ipamDriver = "IpamDriver"
networkDriver = "NetworkDriver"
volumeDriver = "VolumeDriver"
)
// UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType // UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType
func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error { func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error {
versionIndex := len(p) versionIndex := len(p)

View File

@@ -7,7 +7,7 @@ package types
// swagger:model Port // swagger:model Port
type Port struct { type Port struct {
// Host IP address that the container's port is mapped to // IP
IP string `json:"IP,omitempty"` IP string `json:"IP,omitempty"`
// Port on the container // Port on the container

View File

@@ -1,4 +1,4 @@
package registry // import "github.com/docker/docker/api/types/registry" package registry
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE // DO NOT EDIT THIS FILE

View File

@@ -1,16 +1,12 @@
package registry // import "github.com/docker/docker/api/types/registry" package registry
import ( import (
"encoding/json" "encoding/json"
"net" "net"
"github.com/opencontainers/image-spec/specs-go/v1"
) )
// ServiceConfig stores daemon registry services configuration. // ServiceConfig stores daemon registry services configuration.
type ServiceConfig struct { type ServiceConfig struct {
AllowNondistributableArtifactsCIDRs []*NetIPNet
AllowNondistributableArtifactsHostnames []string
InsecureRegistryCIDRs []*NetIPNet `json:"InsecureRegistryCIDRs"` InsecureRegistryCIDRs []*NetIPNet `json:"InsecureRegistryCIDRs"`
IndexConfigs map[string]*IndexInfo `json:"IndexConfigs"` IndexConfigs map[string]*IndexInfo `json:"IndexConfigs"`
Mirrors []string Mirrors []string
@@ -106,14 +102,3 @@ type SearchResults struct {
// Results is a slice containing the actual results for the search // Results is a slice containing the actual results for the search
Results []SearchResult `json:"results"` Results []SearchResult `json:"results"`
} }
// DistributionInspect describes the result obtained from contacting the
// registry to retrieve image metadata
type DistributionInspect struct {
// Descriptor contains information about the manifest, including
// the content addressable digest
Descriptor v1.Descriptor
// Platforms contains the list of platforms supported by the image,
// obtained by parsing the manifest
Platforms []v1.Platform
}

View File

@@ -1,4 +1,4 @@
package types // import "github.com/docker/docker/api/types" package types
// Seccomp represents the config for a seccomp profile for syscall restriction. // Seccomp represents the config for a seccomp profile for syscall restriction.
type Seccomp struct { type Seccomp struct {

View File

@@ -1,6 +1,6 @@
// Package types is used for API stability in the types and response to the // Package types is used for API stability in the types and response to the
// consumers of the API stats endpoint. // consumers of the API stats endpoint.
package types // import "github.com/docker/docker/api/types" package types
import "time" import "time"

View File

@@ -1,4 +1,4 @@
package strslice // import "github.com/docker/docker/api/types/strslice" package strslice
import "encoding/json" import "encoding/json"

View File

@@ -1,4 +1,4 @@
package swarm // import "github.com/docker/docker/api/types/swarm" package swarm
import "time" import "time"
@@ -20,21 +20,8 @@ type Annotations struct {
Labels map[string]string `json:"Labels"` Labels map[string]string `json:"Labels"`
} }
// Driver represents a driver (network, logging, secrets backend). // Driver represents a driver (network, logging).
type Driver struct { type Driver struct {
Name string `json:",omitempty"` Name string `json:",omitempty"`
Options map[string]string `json:",omitempty"` Options map[string]string `json:",omitempty"`
} }
// TLSInfo represents the TLS information about what CA certificate is trusted,
// and who the issuer for a TLS certificate is
type TLSInfo struct {
// TrustRoot is the trusted CA root certificate in PEM format
TrustRoot string `json:",omitempty"`
// CertIssuer is the raw subject bytes of the issuer
CertIssuerSubject []byte `json:",omitempty"`
// CertIssuerPublicKey is the raw public key bytes of the issuer
CertIssuerPublicKey []byte `json:",omitempty"`
}

View File

@@ -1,35 +0,0 @@
package swarm // import "github.com/docker/docker/api/types/swarm"
import "os"
// Config represents a config.
type Config struct {
ID string
Meta
Spec ConfigSpec
}
// ConfigSpec represents a config specification from a config in swarm
type ConfigSpec struct {
Annotations
Data []byte `json:",omitempty"`
// Templating controls whether and how to evaluate the config payload as
// a template. If it is not set, no templating is used.
Templating *Driver `json:",omitempty"`
}
// ConfigReferenceFileTarget is a file target in a config reference
type ConfigReferenceFileTarget struct {
Name string
UID string
GID string
Mode os.FileMode
}
// ConfigReference is a reference to a config in swarm
type ConfigReference struct {
File *ConfigReferenceFileTarget
ConfigID string
ConfigName string
}

View File

@@ -1,4 +1,4 @@
package swarm // import "github.com/docker/docker/api/types/swarm" package swarm
import ( import (
"time" "time"
@@ -55,7 +55,6 @@ type ContainerSpec struct {
User string `json:",omitempty"` User string `json:",omitempty"`
Groups []string `json:",omitempty"` Groups []string `json:",omitempty"`
Privileges *Privileges `json:",omitempty"` Privileges *Privileges `json:",omitempty"`
Init *bool `json:",omitempty"`
StopSignal string `json:",omitempty"` StopSignal string `json:",omitempty"`
TTY bool `json:",omitempty"` TTY bool `json:",omitempty"`
OpenStdin bool `json:",omitempty"` OpenStdin bool `json:",omitempty"`
@@ -69,6 +68,4 @@ type ContainerSpec struct {
Hosts []string `json:",omitempty"` Hosts []string `json:",omitempty"`
DNSConfig *DNSConfig `json:",omitempty"` DNSConfig *DNSConfig `json:",omitempty"`
Secrets []*SecretReference `json:",omitempty"` Secrets []*SecretReference `json:",omitempty"`
Configs []*ConfigReference `json:",omitempty"`
Isolation container.Isolation `json:",omitempty"`
} }

View File

@@ -1,8 +1,4 @@
package swarm // import "github.com/docker/docker/api/types/swarm" package swarm
import (
"github.com/docker/docker/api/types/network"
)
// Endpoint represents an endpoint. // Endpoint represents an endpoint.
type Endpoint struct { type Endpoint struct {
@@ -62,8 +58,6 @@ const (
PortConfigProtocolTCP PortConfigProtocol = "tcp" PortConfigProtocolTCP PortConfigProtocol = "tcp"
// PortConfigProtocolUDP UDP // PortConfigProtocolUDP UDP
PortConfigProtocolUDP PortConfigProtocol = "udp" PortConfigProtocolUDP PortConfigProtocol = "udp"
// PortConfigProtocolSCTP SCTP
PortConfigProtocolSCTP PortConfigProtocol = "sctp"
) )
// EndpointVirtualIP represents the virtual ip of a port. // EndpointVirtualIP represents the virtual ip of a port.
@@ -90,15 +84,12 @@ type NetworkSpec struct {
Attachable bool `json:",omitempty"` Attachable bool `json:",omitempty"`
Ingress bool `json:",omitempty"` Ingress bool `json:",omitempty"`
IPAMOptions *IPAMOptions `json:",omitempty"` IPAMOptions *IPAMOptions `json:",omitempty"`
ConfigFrom *network.ConfigReference `json:",omitempty"`
Scope string `json:",omitempty"`
} }
// NetworkAttachmentConfig represents the configuration of a network attachment. // NetworkAttachmentConfig represents the configuration of a network attachment.
type NetworkAttachmentConfig struct { type NetworkAttachmentConfig struct {
Target string `json:",omitempty"` Target string `json:",omitempty"`
Aliases []string `json:",omitempty"` Aliases []string `json:",omitempty"`
DriverOpts map[string]string `json:",omitempty"`
} }
// NetworkAttachment represents a network attachment. // NetworkAttachment represents a network attachment.

View File

@@ -1,4 +1,4 @@
package swarm // import "github.com/docker/docker/api/types/swarm" package swarm
// Node represents a node. // Node represents a node.
type Node struct { type Node struct {
@@ -52,7 +52,6 @@ type NodeDescription struct {
Platform Platform `json:",omitempty"` Platform Platform `json:",omitempty"`
Resources Resources `json:",omitempty"` Resources Resources `json:",omitempty"`
Engine EngineDescription `json:",omitempty"` Engine EngineDescription `json:",omitempty"`
TLSInfo TLSInfo `json:",omitempty"`
} }
// Platform represents the platform (Arch/OS). // Platform represents the platform (Arch/OS).

View File

@@ -1,27 +0,0 @@
package swarm // import "github.com/docker/docker/api/types/swarm"
// RuntimeType is the type of runtime used for the TaskSpec
type RuntimeType string
// RuntimeURL is the proto type url
type RuntimeURL string
const (
// RuntimeContainer is the container based runtime
RuntimeContainer RuntimeType = "container"
// RuntimePlugin is the plugin based runtime
RuntimePlugin RuntimeType = "plugin"
// RuntimeNetworkAttachment is the network attachment runtime
RuntimeNetworkAttachment RuntimeType = "attachment"
// RuntimeURLContainer is the proto url for the container type
RuntimeURLContainer RuntimeURL = "types.docker.com/RuntimeContainer"
// RuntimeURLPlugin is the proto url for the plugin type
RuntimeURLPlugin RuntimeURL = "types.docker.com/RuntimePlugin"
)
// NetworkAttachmentSpec represents the runtime spec type for network
// attachment tasks
type NetworkAttachmentSpec struct {
ContainerID string
}

View File

@@ -1,3 +0,0 @@
//go:generate protoc -I . --gogofast_out=import_path=github.com/docker/docker/api/types/swarm/runtime:. plugin.proto
package runtime // import "github.com/docker/docker/api/types/swarm/runtime"

View File

@@ -1,712 +0,0 @@
// Code generated by protoc-gen-gogo.
// source: plugin.proto
// DO NOT EDIT!
/*
Package runtime is a generated protocol buffer package.
It is generated from these files:
plugin.proto
It has these top-level messages:
PluginSpec
PluginPrivilege
*/
package runtime
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
// PluginSpec defines the base payload which clients can specify for creating
// a service with the plugin runtime.
type PluginSpec struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Remote string `protobuf:"bytes,2,opt,name=remote,proto3" json:"remote,omitempty"`
Privileges []*PluginPrivilege `protobuf:"bytes,3,rep,name=privileges" json:"privileges,omitempty"`
Disabled bool `protobuf:"varint,4,opt,name=disabled,proto3" json:"disabled,omitempty"`
}
func (m *PluginSpec) Reset() { *m = PluginSpec{} }
func (m *PluginSpec) String() string { return proto.CompactTextString(m) }
func (*PluginSpec) ProtoMessage() {}
func (*PluginSpec) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{0} }
func (m *PluginSpec) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *PluginSpec) GetRemote() string {
if m != nil {
return m.Remote
}
return ""
}
func (m *PluginSpec) GetPrivileges() []*PluginPrivilege {
if m != nil {
return m.Privileges
}
return nil
}
func (m *PluginSpec) GetDisabled() bool {
if m != nil {
return m.Disabled
}
return false
}
// PluginPrivilege describes a permission the user has to accept
// upon installing a plugin.
type PluginPrivilege struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
Value []string `protobuf:"bytes,3,rep,name=value" json:"value,omitempty"`
}
func (m *PluginPrivilege) Reset() { *m = PluginPrivilege{} }
func (m *PluginPrivilege) String() string { return proto.CompactTextString(m) }
func (*PluginPrivilege) ProtoMessage() {}
func (*PluginPrivilege) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{1} }
func (m *PluginPrivilege) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *PluginPrivilege) GetDescription() string {
if m != nil {
return m.Description
}
return ""
}
func (m *PluginPrivilege) GetValue() []string {
if m != nil {
return m.Value
}
return nil
}
func init() {
proto.RegisterType((*PluginSpec)(nil), "PluginSpec")
proto.RegisterType((*PluginPrivilege)(nil), "PluginPrivilege")
}
func (m *PluginSpec) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *PluginSpec) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Name) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name)))
i += copy(dAtA[i:], m.Name)
}
if len(m.Remote) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Remote)))
i += copy(dAtA[i:], m.Remote)
}
if len(m.Privileges) > 0 {
for _, msg := range m.Privileges {
dAtA[i] = 0x1a
i++
i = encodeVarintPlugin(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
if m.Disabled {
dAtA[i] = 0x20
i++
if m.Disabled {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
return i, nil
}
func (m *PluginPrivilege) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *PluginPrivilege) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Name) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name)))
i += copy(dAtA[i:], m.Name)
}
if len(m.Description) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintPlugin(dAtA, i, uint64(len(m.Description)))
i += copy(dAtA[i:], m.Description)
}
if len(m.Value) > 0 {
for _, s := range m.Value {
dAtA[i] = 0x1a
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
return i, nil
}
func encodeFixed64Plugin(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
dAtA[offset+4] = uint8(v >> 32)
dAtA[offset+5] = uint8(v >> 40)
dAtA[offset+6] = uint8(v >> 48)
dAtA[offset+7] = uint8(v >> 56)
return offset + 8
}
func encodeFixed32Plugin(dAtA []byte, offset int, v uint32) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
return offset + 4
}
func encodeVarintPlugin(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *PluginSpec) Size() (n int) {
var l int
_ = l
l = len(m.Name)
if l > 0 {
n += 1 + l + sovPlugin(uint64(l))
}
l = len(m.Remote)
if l > 0 {
n += 1 + l + sovPlugin(uint64(l))
}
if len(m.Privileges) > 0 {
for _, e := range m.Privileges {
l = e.Size()
n += 1 + l + sovPlugin(uint64(l))
}
}
if m.Disabled {
n += 2
}
return n
}
func (m *PluginPrivilege) Size() (n int) {
var l int
_ = l
l = len(m.Name)
if l > 0 {
n += 1 + l + sovPlugin(uint64(l))
}
l = len(m.Description)
if l > 0 {
n += 1 + l + sovPlugin(uint64(l))
}
if len(m.Value) > 0 {
for _, s := range m.Value {
l = len(s)
n += 1 + l + sovPlugin(uint64(l))
}
}
return n
}
func sovPlugin(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozPlugin(x uint64) (n int) {
return sovPlugin(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *PluginSpec) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: PluginSpec: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: PluginSpec: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Remote", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Remote = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Privileges", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Privileges = append(m.Privileges, &PluginPrivilege{})
if err := m.Privileges[len(m.Privileges)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Disabled", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Disabled = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipPlugin(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthPlugin
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *PluginPrivilege) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: PluginPrivilege: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: PluginPrivilege: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Description = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Value = append(m.Value, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipPlugin(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthPlugin
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipPlugin(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowPlugin
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowPlugin
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowPlugin
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthPlugin
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowPlugin
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipPlugin(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthPlugin = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowPlugin = fmt.Errorf("proto: integer overflow")
)
func init() { proto.RegisterFile("plugin.proto", fileDescriptorPlugin) }
var fileDescriptorPlugin = []byte{
// 196 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0xc8, 0x29, 0x4d,
0xcf, 0xcc, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x6a, 0x63, 0xe4, 0xe2, 0x0a, 0x00, 0x0b,
0x04, 0x17, 0xa4, 0x26, 0x0b, 0x09, 0x71, 0xb1, 0xe4, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x2a, 0x30,
0x6a, 0x70, 0x06, 0x81, 0xd9, 0x42, 0x62, 0x5c, 0x6c, 0x45, 0xa9, 0xb9, 0xf9, 0x25, 0xa9, 0x12,
0x4c, 0x60, 0x51, 0x28, 0x4f, 0xc8, 0x80, 0x8b, 0xab, 0xa0, 0x28, 0xb3, 0x2c, 0x33, 0x27, 0x35,
0x3d, 0xb5, 0x58, 0x82, 0x59, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x40, 0x0f, 0x62, 0x58, 0x00, 0x4c,
0x22, 0x08, 0x49, 0x8d, 0x90, 0x14, 0x17, 0x47, 0x4a, 0x66, 0x71, 0x62, 0x52, 0x4e, 0x6a, 0x8a,
0x04, 0x8b, 0x02, 0xa3, 0x06, 0x47, 0x10, 0x9c, 0xaf, 0x14, 0xcb, 0xc5, 0x8f, 0xa6, 0x15, 0xab,
0x63, 0x14, 0xb8, 0xb8, 0x53, 0x52, 0x8b, 0x93, 0x8b, 0x32, 0x0b, 0x4a, 0x32, 0xf3, 0xf3, 0xa0,
0x2e, 0x42, 0x16, 0x12, 0x12, 0xe1, 0x62, 0x2d, 0x4b, 0xcc, 0x29, 0x4d, 0x05, 0xbb, 0x88, 0x33,
0x08, 0xc2, 0x71, 0xe2, 0x39, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4,
0x18, 0x93, 0xd8, 0xc0, 0x9e, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xb8, 0x84, 0xad, 0x79,
0x0c, 0x01, 0x00, 0x00,
}

View File

@@ -1,20 +0,0 @@
syntax = "proto3";
option go_package = "github.com/docker/docker/api/types/swarm/runtime;runtime";
// PluginSpec defines the base payload which clients can specify for creating
// a service with the plugin runtime.
message PluginSpec {
string name = 1;
string remote = 2;
repeated PluginPrivilege privileges = 3;
bool disabled = 4;
}
// PluginPrivilege describes a permission the user has to accept
// upon installing a plugin.
message PluginPrivilege {
string name = 1;
string description = 2;
repeated string value = 3;
}

View File

@@ -1,4 +1,4 @@
package swarm // import "github.com/docker/docker/api/types/swarm" package swarm
import "os" import "os"
@@ -13,11 +13,6 @@ type Secret struct {
type SecretSpec struct { type SecretSpec struct {
Annotations Annotations
Data []byte `json:",omitempty"` Data []byte `json:",omitempty"`
Driver *Driver `json:",omitempty"` // name of the secrets driver used to fetch the secret's value from an external secret store
// Templating controls whether and how to evaluate the secret payload as
// a template. If it is not set, no templating is used.
Templating *Driver `json:",omitempty"`
} }
// SecretReferenceFileTarget is a file target in a secret reference // SecretReferenceFileTarget is a file target in a secret reference

View File

@@ -1,4 +1,4 @@
package swarm // import "github.com/docker/docker/api/types/swarm" package swarm
import "time" import "time"

View File

@@ -1,15 +1,13 @@
package swarm // import "github.com/docker/docker/api/types/swarm" package swarm
import "time" import "time"
// ClusterInfo represents info about the cluster for outputting in "info" // ClusterInfo represents info about the cluster for outputing in "info"
// it contains the same information as "Swarm", but without the JoinTokens // it contains the same information as "Swarm", but without the JoinTokens
type ClusterInfo struct { type ClusterInfo struct {
ID string ID string
Meta Meta
Spec Spec Spec Spec
TLSInfo TLSInfo
RootRotationInProgress bool
} }
// Swarm represents a swarm. // Swarm represents a swarm.
@@ -109,16 +107,6 @@ type CAConfig struct {
// ExternalCAs is a list of CAs to which a manager node will make // ExternalCAs is a list of CAs to which a manager node will make
// certificate signing requests for node certificates. // certificate signing requests for node certificates.
ExternalCAs []*ExternalCA `json:",omitempty"` ExternalCAs []*ExternalCA `json:",omitempty"`
// SigningCACert and SigningCAKey specify the desired signing root CA and
// root CA key for the swarm. When inspecting the cluster, the key will
// be redacted.
SigningCACert string `json:",omitempty"`
SigningCAKey string `json:",omitempty"`
// If this value changes, and there is no specified signing cert and key,
// then the swarm is forced to generate a new root certificate ane key.
ForceRotate uint64 `json:",omitempty"`
} }
// ExternalCAProtocol represents type of external CA. // ExternalCAProtocol represents type of external CA.
@@ -138,17 +126,12 @@ type ExternalCA struct {
// Options is a set of additional key/value pairs whose interpretation // Options is a set of additional key/value pairs whose interpretation
// depends on the specified CA type. // depends on the specified CA type.
Options map[string]string `json:",omitempty"` Options map[string]string `json:",omitempty"`
// CACert specifies which root CA is used by this external CA. This certificate must
// be in PEM format.
CACert string
} }
// InitRequest is the request used to init a swarm. // InitRequest is the request used to init a swarm.
type InitRequest struct { type InitRequest struct {
ListenAddr string ListenAddr string
AdvertiseAddr string AdvertiseAddr string
DataPathAddr string
ForceNewCluster bool ForceNewCluster bool
Spec Spec Spec Spec
AutoLockManagers bool AutoLockManagers bool
@@ -159,7 +142,6 @@ type InitRequest struct {
type JoinRequest struct { type JoinRequest struct {
ListenAddr string ListenAddr string
AdvertiseAddr string AdvertiseAddr string
DataPathAddr string
RemoteAddrs []string RemoteAddrs []string
JoinToken string // accept by secret JoinToken string // accept by secret
Availability NodeAvailability Availability NodeAvailability

View File

@@ -1,10 +1,6 @@
package swarm // import "github.com/docker/docker/api/types/swarm" package swarm
import ( import "time"
"time"
"github.com/docker/docker/api/types/swarm/runtime"
)
// TaskState represents the state of a task. // TaskState represents the state of a task.
type TaskState string type TaskState string
@@ -36,10 +32,6 @@ const (
TaskStateFailed TaskState = "failed" TaskStateFailed TaskState = "failed"
// TaskStateRejected REJECTED // TaskStateRejected REJECTED
TaskStateRejected TaskState = "rejected" TaskStateRejected TaskState = "rejected"
// TaskStateRemove REMOVE
TaskStateRemove TaskState = "remove"
// TaskStateOrphaned ORPHANED
TaskStateOrphaned TaskState = "orphaned"
) )
// Task represents a task. // Task represents a task.
@@ -55,19 +47,11 @@ type Task struct {
Status TaskStatus `json:",omitempty"` Status TaskStatus `json:",omitempty"`
DesiredState TaskState `json:",omitempty"` DesiredState TaskState `json:",omitempty"`
NetworksAttachments []NetworkAttachment `json:",omitempty"` NetworksAttachments []NetworkAttachment `json:",omitempty"`
GenericResources []GenericResource `json:",omitempty"`
} }
// TaskSpec represents the spec of a task. // TaskSpec represents the spec of a task.
type TaskSpec struct { type TaskSpec struct {
// ContainerSpec, NetworkAttachmentSpec, and PluginSpec are mutually exclusive. ContainerSpec ContainerSpec `json:",omitempty"`
// PluginSpec is only used when the `Runtime` field is set to `plugin`
// NetworkAttachmentSpec is used if the `Runtime` field is set to
// `attachment`.
ContainerSpec *ContainerSpec `json:",omitempty"`
PluginSpec *runtime.PluginSpec `json:",omitempty"`
NetworkAttachmentSpec *NetworkAttachmentSpec `json:",omitempty"`
Resources *ResourceRequirements `json:",omitempty"` Resources *ResourceRequirements `json:",omitempty"`
RestartPolicy *RestartPolicy `json:",omitempty"` RestartPolicy *RestartPolicy `json:",omitempty"`
Placement *Placement `json:",omitempty"` Placement *Placement `json:",omitempty"`
@@ -81,40 +65,12 @@ type TaskSpec struct {
// ForceUpdate is a counter that triggers an update even if no relevant // ForceUpdate is a counter that triggers an update even if no relevant
// parameters have been changed. // parameters have been changed.
ForceUpdate uint64 ForceUpdate uint64
Runtime RuntimeType `json:",omitempty"`
} }
// Resources represents resources (CPU/Memory). // Resources represents resources (CPU/Memory).
type Resources struct { type Resources struct {
NanoCPUs int64 `json:",omitempty"` NanoCPUs int64 `json:",omitempty"`
MemoryBytes int64 `json:",omitempty"` MemoryBytes int64 `json:",omitempty"`
GenericResources []GenericResource `json:",omitempty"`
}
// GenericResource represents a "user defined" resource which can
// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1)
type GenericResource struct {
NamedResourceSpec *NamedGenericResource `json:",omitempty"`
DiscreteResourceSpec *DiscreteGenericResource `json:",omitempty"`
}
// NamedGenericResource represents a "user defined" resource which is defined
// as a string.
// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
// Value is used to identify the resource (GPU="UUID-1", FPGA="/dev/sdb5", ...)
type NamedGenericResource struct {
Kind string `json:",omitempty"`
Value string `json:",omitempty"`
}
// DiscreteGenericResource represents a "user defined" resource which is defined
// as an integer
// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
// Value is used to count the resource (SSD=5, HDD=3, ...)
type DiscreteGenericResource struct {
Kind string `json:",omitempty"`
Value int64 `json:",omitempty"`
} }
// ResourceRequirements represents resources requirements. // ResourceRequirements represents resources requirements.
@@ -127,11 +83,6 @@ type ResourceRequirements struct {
type Placement struct { type Placement struct {
Constraints []string `json:",omitempty"` Constraints []string `json:",omitempty"`
Preferences []PlacementPreference `json:",omitempty"` Preferences []PlacementPreference `json:",omitempty"`
// Platforms stores all the platforms that the image can run on.
// This field is used in the platform filter for scheduling. If empty,
// then the platform filter is off, meaning there are no scheduling restrictions.
Platforms []Platform `json:",omitempty"`
} }
// PlacementPreference provides a way to make the scheduler aware of factors // PlacementPreference provides a way to make the scheduler aware of factors
@@ -173,15 +124,15 @@ type TaskStatus struct {
State TaskState `json:",omitempty"` State TaskState `json:",omitempty"`
Message string `json:",omitempty"` Message string `json:",omitempty"`
Err string `json:",omitempty"` Err string `json:",omitempty"`
ContainerStatus *ContainerStatus `json:",omitempty"` ContainerStatus ContainerStatus `json:",omitempty"`
PortStatus PortStatus `json:",omitempty"` PortStatus PortStatus `json:",omitempty"`
} }
// ContainerStatus represents the status of a container. // ContainerStatus represents the status of a container.
type ContainerStatus struct { type ContainerStatus struct {
ContainerID string ContainerID string `json:",omitempty"`
PID int PID int `json:",omitempty"`
ExitCode int ExitCode int `json:",omitempty"`
} }
// PortStatus represents the port status of a task's host ports whose // PortStatus represents the port status of a task's host ports whose

View File

@@ -1,4 +1,4 @@
package time // import "github.com/docker/docker/api/types/time" package time
import ( import (
"strconv" "strconv"

View File

@@ -1,4 +1,4 @@
package time // import "github.com/docker/docker/api/types/time" package time
import ( import (
"fmt" "fmt"
@@ -29,8 +29,10 @@ func GetTimestamp(value string, reference time.Time) (string, error) {
} }
var format string var format string
var parseInLocation bool
// if the string has a Z or a + or three dashes use parse otherwise use parseinlocation // if the string has a Z or a + or three dashes use parse otherwise use parseinlocation
parseInLocation := !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3) parseInLocation = !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3)
if strings.Contains(value, ".") { if strings.Contains(value, ".") {
if parseInLocation { if parseInLocation {
@@ -82,14 +84,11 @@ func GetTimestamp(value string, reference time.Time) (string, error) {
} }
if err != nil { if err != nil {
// if there is a `-` then it's an RFC3339 like timestamp // if there is a `-` then it's an RFC3339 like timestamp otherwise assume unixtimestamp
if strings.Contains(value, "-") { if strings.Contains(value, "-") {
return "", err // was probably an RFC3339 like timestamp but the parser failed with an error return "", err // was probably an RFC3339 like timestamp but the parser failed with an error
} }
if _, _, err := parseTimestamp(value); err != nil { return value, nil // unixtimestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server)
return "", fmt.Errorf("failed to parse value as time or duration: %q", value)
}
return value, nil // unix timestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server)
} }
return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())), nil return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())), nil
@@ -107,10 +106,6 @@ func ParseTimestamps(value string, def int64) (int64, int64, error) {
if value == "" { if value == "" {
return def, 0, nil return def, 0, nil
} }
return parseTimestamp(value)
}
func parseTimestamp(value string) (int64, int64, error) {
sa := strings.SplitN(value, ".", 2) sa := strings.SplitN(value, ".", 2)
s, err := strconv.ParseInt(sa[0], 10, 64) s, err := strconv.ParseInt(sa[0], 10, 64)
if err != nil { if err != nil {

View File

@@ -1,4 +1,4 @@
package types // import "github.com/docker/docker/api/types" package types
import ( import (
"errors" "errors"
@@ -45,12 +45,6 @@ type ImageInspect struct {
VirtualSize int64 VirtualSize int64
GraphDriver GraphDriverData GraphDriver GraphDriverData
RootFS RootFS RootFS RootFS
Metadata ImageMetadata
}
// ImageMetadata contains engine-local data about the image
type ImageMetadata struct {
LastTagTime time.Time `json:",omitempty"`
} }
// Container contains response of Engine API: // Container contains response of Engine API:
@@ -107,21 +101,9 @@ type Ping struct {
Experimental bool Experimental bool
} }
// ComponentVersion describes the version information for a specific component.
type ComponentVersion struct {
Name string
Version string
Details map[string]string `json:",omitempty"`
}
// Version contains response of Engine API: // Version contains response of Engine API:
// GET "/version" // GET "/version"
type Version struct { type Version struct {
Platform struct{ Name string } `json:",omitempty"`
Components []ComponentVersion `json:",omitempty"`
// The following fields are deprecated, they relate to the Engine component and are kept for backwards compatibility
Version string Version string
APIVersion string `json:"ApiVersion"` APIVersion string `json:"ApiVersion"`
MinAPIVersion string `json:"MinAPIVersion,omitempty"` MinAPIVersion string `json:"MinAPIVersion,omitempty"`
@@ -180,7 +162,6 @@ type Info struct {
RegistryConfig *registry.ServiceConfig RegistryConfig *registry.ServiceConfig
NCPU int NCPU int
MemTotal int64 MemTotal int64
GenericResources []swarm.GenericResource
DockerRootDir string DockerRootDir string
HTTPProxy string `json:"HttpProxy"` HTTPProxy string `json:"HttpProxy"`
HTTPSProxy string `json:"HttpsProxy"` HTTPSProxy string `json:"HttpsProxy"`
@@ -257,8 +238,6 @@ type PluginsInfo struct {
Network []string Network []string
// List of Authorization plugins registered // List of Authorization plugins registered
Authorization []string Authorization []string
// List of Log plugins registered
Log []string
} }
// ExecStartCheck is a temp struct used by execStart // ExecStartCheck is a temp struct used by execStart
@@ -296,7 +275,7 @@ type Health struct {
// ContainerState stores container's running state // ContainerState stores container's running state
// it's part of ContainerJSONBase and will return by "inspect" command // it's part of ContainerJSONBase and will return by "inspect" command
type ContainerState struct { type ContainerState struct {
Status string // String representation of the container state. Can be one of "created", "running", "paused", "restarting", "removing", "exited", or "dead" Status string
Running bool Running bool
Paused bool Paused bool
Restarting bool Restarting bool
@@ -339,7 +318,6 @@ type ContainerJSONBase struct {
Name string Name string
RestartCount int RestartCount int
Driver string Driver string
Platform string
MountLabel string MountLabel string
ProcessLabel string ProcessLabel string
AppArmorProfile string AppArmorProfile string
@@ -416,15 +394,13 @@ type NetworkResource struct {
Name string // Name is the requested name of the network Name string // Name is the requested name of the network
ID string `json:"Id"` // ID uniquely identifies a network on a single machine ID string `json:"Id"` // ID uniquely identifies a network on a single machine
Created time.Time // Created is the time the network created Created time.Time // Created is the time the network created
Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level) Scope string // Scope describes the level at which the network exists (e.g. `global` for cluster-wide or `local` for machine level)
Driver string // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`) Driver string // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`)
EnableIPv6 bool // EnableIPv6 represents whether to enable IPv6 EnableIPv6 bool // EnableIPv6 represents whether to enable IPv6
IPAM network.IPAM // IPAM is the network's IP Address Management IPAM network.IPAM // IPAM is the network's IP Address Management
Internal bool // Internal represents if the network is used internal only Internal bool // Internal represents if the network is used internal only
Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode. Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode.
Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster. Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster.
ConfigFrom network.ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network.
ConfigOnly bool // ConfigOnly networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services.
Containers map[string]EndpointResource // Containers contains endpoints belonging to the network Containers map[string]EndpointResource // Containers contains endpoints belonging to the network
Options map[string]string // Options holds the network specific options to use for when creating the network Options map[string]string // Options holds the network specific options to use for when creating the network
Labels map[string]string // Labels holds metadata specific to the network being created Labels map[string]string // Labels holds metadata specific to the network being created
@@ -452,14 +428,11 @@ type NetworkCreate struct {
// which has the same name but it is not guaranteed to catch all name collisions. // which has the same name but it is not guaranteed to catch all name collisions.
CheckDuplicate bool CheckDuplicate bool
Driver string Driver string
Scope string
EnableIPv6 bool EnableIPv6 bool
IPAM *network.IPAM IPAM *network.IPAM
Internal bool Internal bool
Attachable bool Attachable bool
Ingress bool Ingress bool
ConfigOnly bool
ConfigFrom *network.ConfigReference
Options map[string]string Options map[string]string
Labels map[string]string Labels map[string]string
} }
@@ -488,12 +461,6 @@ type NetworkDisconnect struct {
Force bool Force bool
} }
// NetworkInspectOptions holds parameters to inspect network
type NetworkInspectOptions struct {
Scope string
Verbose bool
}
// Checkpoint represents the details of a checkpoint // Checkpoint represents the details of a checkpoint
type Checkpoint struct { type Checkpoint struct {
Name string // Name is the name of the checkpoint Name string // Name is the name of the checkpoint
@@ -512,8 +479,6 @@ type DiskUsage struct {
Images []*ImageSummary Images []*ImageSummary
Containers []*Container Containers []*Container
Volumes []*Volume Volumes []*Volume
BuildCache []*BuildCache
BuilderSize int64 // deprecated
} }
// ContainersPruneReport contains the response for Engine API: // ContainersPruneReport contains the response for Engine API:
@@ -537,12 +502,6 @@ type ImagesPruneReport struct {
SpaceReclaimed uint64 SpaceReclaimed uint64
} }
// BuildCachePruneReport contains the response for Engine API:
// POST "/build/prune"
type BuildCachePruneReport struct {
SpaceReclaimed uint64
}
// NetworksPruneReport contains the response for Engine API: // NetworksPruneReport contains the response for Engine API:
// POST "/networks/prune" // POST "/networks/prune"
type NetworksPruneReport struct { type NetworksPruneReport struct {
@@ -561,18 +520,6 @@ type SecretListOptions struct {
Filters filters.Args Filters filters.Args
} }
// ConfigCreateResponse contains the information returned to a client
// on the creation of a new config.
type ConfigCreateResponse struct {
// ID is the id of the created config.
ID string
}
// ConfigListOptions holds parameters to list configs
type ConfigListOptions struct {
Filters filters.Args
}
// PushResult contains the tag, manifest digest, and manifest size from the // PushResult contains the tag, manifest digest, and manifest size from the
// push. It's used to signal this information to the trust code in the client // push. It's used to signal this information to the trust code in the client
// so it can sign the manifest if necessary. // so it can sign the manifest if necessary.
@@ -581,22 +528,3 @@ type PushResult struct {
Digest string Digest string
Size int Size int
} }
// BuildResult contains the image id of a successful build
type BuildResult struct {
ID string
}
// BuildCache contains information about a build cache record
type BuildCache struct {
ID string
Mutable bool
InUse bool
Size int64
CreatedAt time.Time
LastUsedAt *time.Time
UsageCount int
Parent string
Description string
}

View File

@@ -1,4 +1,4 @@
package versions // import "github.com/docker/docker/api/types/versions" package versions
import ( import (
"strconv" "strconv"

View File

@@ -7,9 +7,6 @@ package types
// swagger:model Volume // swagger:model Volume
type Volume struct { type Volume struct {
// Date/Time the volume was created.
CreatedAt string `json:"CreatedAt,omitempty"`
// Name of the volume driver used by the volume. // Name of the volume driver used by the volume.
// Required: true // Required: true
Driver string `json:"Driver"` Driver string `json:"Driver"`
@@ -47,23 +44,15 @@ type Volume struct {
UsageData *VolumeUsageData `json:"UsageData,omitempty"` UsageData *VolumeUsageData `json:"UsageData,omitempty"`
} }
// VolumeUsageData Usage details about the volume. This information is used by the // VolumeUsageData volume usage data
// `GET /system/df` endpoint, and omitted in other endpoints.
//
// swagger:model VolumeUsageData // swagger:model VolumeUsageData
type VolumeUsageData struct { type VolumeUsageData struct {
// The number of containers referencing this volume. This field // The number of containers referencing this volume.
// is set to `-1` if the reference-count is not available.
//
// Required: true // Required: true
RefCount int64 `json:"RefCount"` RefCount int64 `json:"RefCount"`
// Amount of disk space used by the volume (in bytes). This information // The disk space used by the volume (local driver only)
// is only available for volumes created with the `"local"` volume
// driver. For volumes created with other volume drivers, this field
// is set to `-1` ("not available")
//
// Required: true // Required: true
Size int64 `json:"Size"` Size int64 `json:"Size"`
} }

View File

@@ -7,9 +7,9 @@ package volume
// See hack/generate-swagger-api.sh // See hack/generate-swagger-api.sh
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// VolumeCreateBody // VolumesCreateBody volumes create body
// swagger:model VolumeCreateBody // swagger:model VolumesCreateBody
type VolumeCreateBody struct { type VolumesCreateBody struct {
// Name of the volume driver to use. // Name of the volume driver to use.
// Required: true // Required: true

View File

@@ -9,9 +9,9 @@ package volume
import "github.com/docker/docker/api/types" import "github.com/docker/docker/api/types"
// VolumeListOKBody // VolumesListOKBody volumes list o k body
// swagger:model VolumeListOKBody // swagger:model VolumesListOKBody
type VolumeListOKBody struct { type VolumesListOKBody struct {
// List of volumes // List of volumes
// Required: true // Required: true

View File

@@ -1,21 +0,0 @@
package client // import "github.com/docker/docker/client"
import (
"net/url"
"golang.org/x/net/context"
)
// BuildCancel requests the daemon to cancel ongoing build request
func (cli *Client) BuildCancel(ctx context.Context, id string) error {
query := url.Values{}
query.Set("id", id)
serverResp, err := cli.post(ctx, "/build/cancel", query, nil, nil)
if err != nil {
return err
}
defer ensureReaderClosed(serverResp)
return nil
}

View File

@@ -1,30 +0,0 @@
package client // import "github.com/docker/docker/client"
import (
"context"
"encoding/json"
"fmt"
"github.com/docker/docker/api/types"
)
// BuildCachePrune requests the daemon to delete unused cache data
func (cli *Client) BuildCachePrune(ctx context.Context) (*types.BuildCachePruneReport, error) {
if err := cli.NewVersionError("1.31", "build prune"); err != nil {
return nil, err
}
report := types.BuildCachePruneReport{}
serverResp, err := cli.post(ctx, "/build/prune", nil, nil, nil)
if err != nil {
return nil, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
return nil, fmt.Errorf("Error retrieving disk usage: %v", err)
}
return &report, nil
}

View File

@@ -1,9 +1,8 @@
package client // import "github.com/docker/docker/client" package client
import ( import (
"context"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"golang.org/x/net/context"
) )
// CheckpointCreate creates a checkpoint from the given container with the given name // CheckpointCreate creates a checkpoint from the given container with the given name

View File

@@ -1,10 +1,10 @@
package client // import "github.com/docker/docker/client" package client
import ( import (
"context"
"net/url" "net/url"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"golang.org/x/net/context"
) )
// CheckpointDelete deletes the checkpoint with the given name from the given container // CheckpointDelete deletes the checkpoint with the given name from the given container

View File

@@ -1,11 +1,12 @@
package client // import "github.com/docker/docker/client" package client
import ( import (
"context"
"encoding/json" "encoding/json"
"net/http"
"net/url" "net/url"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"golang.org/x/net/context"
) )
// CheckpointList returns the checkpoints of the given container in the docker host // CheckpointList returns the checkpoints of the given container in the docker host
@@ -19,7 +20,10 @@ func (cli *Client) CheckpointList(ctx context.Context, container string, options
resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil) resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil)
if err != nil { if err != nil {
return checkpoints, wrapResponseError(err, resp, "container", container) if resp.statusCode == http.StatusNotFound {
return checkpoints, containerNotFoundError{container}
}
return checkpoints, err
} }
err = json.NewDecoder(resp.body).Decode(&checkpoints) err = json.NewDecoder(resp.body).Decode(&checkpoints)

View File

@@ -1,6 +1,10 @@
/* /*
Package client is a Go client for the Docker Engine API. Package client is a Go client for the Docker Engine API.
The "docker" command uses this package to communicate with the daemon. It can also
be used by your own Go applications to do anything the command-line interface does
- running containers, pulling images, managing swarms, etc.
For more information about the Engine API, see the documentation: For more information about the Engine API, see the documentation:
https://docs.docker.com/engine/reference/api/ https://docs.docker.com/engine/reference/api/
@@ -39,30 +43,21 @@ For example, to list running containers (the equivalent of "docker ps"):
} }
*/ */
package client // import "github.com/docker/docker/client" package client
import ( import (
"context"
"fmt" "fmt"
"net"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/docker/docker/api" "github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/versions"
"github.com/docker/go-connections/sockets" "github.com/docker/go-connections/sockets"
"github.com/docker/go-connections/tlsconfig" "github.com/docker/go-connections/tlsconfig"
"github.com/pkg/errors"
) )
// ErrRedirect is the error returned by checkRedirect when the request is non-GET.
var ErrRedirect = errors.New("unexpected redirect in response")
// Client is the API client that performs all operations // Client is the API client that performs all operations
// against a docker server. // against a docker server.
type Client struct { type Client struct {
@@ -86,39 +81,13 @@ type Client struct {
manualOverride bool manualOverride bool
} }
// CheckRedirect specifies the policy for dealing with redirect responses:
// If the request is non-GET return `ErrRedirect`. Otherwise use the last response.
//
// Go 1.8 changes behavior for HTTP redirects (specifically 301, 307, and 308) in the client .
// The Docker client (and by extension docker API client) can be made to to send a request
// like POST /containers//start where what would normally be in the name section of the URL is empty.
// This triggers an HTTP 301 from the daemon.
// In go 1.8 this 301 will be converted to a GET request, and ends up getting a 404 from the daemon.
// This behavior change manifests in the client in that before the 301 was not followed and
// the client did not generate an error, but now results in a message like Error response from daemon: page not found.
func CheckRedirect(req *http.Request, via []*http.Request) error {
if via[0].Method == http.MethodGet {
return http.ErrUseLastResponse
}
return ErrRedirect
}
// NewEnvClient initializes a new API client based on environment variables. // NewEnvClient initializes a new API client based on environment variables.
// See FromEnv for a list of support environment variables. // Use DOCKER_HOST to set the url to the docker server.
// // Use DOCKER_API_VERSION to set the version of the API to reach, leave empty for latest.
// Deprecated: use NewClientWithOpts(FromEnv) // Use DOCKER_CERT_PATH to load the TLS certificates from.
// Use DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default.
func NewEnvClient() (*Client, error) { func NewEnvClient() (*Client, error) {
return NewClientWithOpts(FromEnv) var client *http.Client
}
// FromEnv configures the client with values from environment variables.
//
// Supported environment variables:
// DOCKER_HOST to set the url to the docker server.
// DOCKER_API_VERSION to set the version of the API to reach, leave empty for latest.
// DOCKER_CERT_PATH to load the TLS certificates from.
// DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default.
func FromEnv(c *Client) error {
if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); dockerCertPath != "" { if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); dockerCertPath != "" {
options := tlsconfig.Options{ options := tlsconfig.Options{
CAFile: filepath.Join(dockerCertPath, "ca.pem"), CAFile: filepath.Join(dockerCertPath, "ca.pem"),
@@ -127,160 +96,34 @@ func FromEnv(c *Client) error {
InsecureSkipVerify: os.Getenv("DOCKER_TLS_VERIFY") == "", InsecureSkipVerify: os.Getenv("DOCKER_TLS_VERIFY") == "",
} }
tlsc, err := tlsconfig.Client(options) tlsc, err := tlsconfig.Client(options)
if err != nil {
return err
}
c.client = &http.Client{
Transport: &http.Transport{TLSClientConfig: tlsc},
CheckRedirect: CheckRedirect,
}
}
if host := os.Getenv("DOCKER_HOST"); host != "" {
if err := WithHost(host)(c); err != nil {
return err
}
}
if version := os.Getenv("DOCKER_API_VERSION"); version != "" {
c.version = version
c.manualOverride = true
}
return nil
}
// WithTLSClientConfig applies a tls config to the client transport.
func WithTLSClientConfig(cacertPath, certPath, keyPath string) func(*Client) error {
return func(c *Client) error {
opts := tlsconfig.Options{
CAFile: cacertPath,
CertFile: certPath,
KeyFile: keyPath,
ExclusiveRootPools: true,
}
config, err := tlsconfig.Client(opts)
if err != nil {
return errors.Wrap(err, "failed to create tls config")
}
if transport, ok := c.client.Transport.(*http.Transport); ok {
transport.TLSClientConfig = config
return nil
}
return errors.Errorf("cannot apply tls config to transport: %T", c.client.Transport)
}
}
// WithDialer applies the dialer.DialContext to the client transport. This can be
// used to set the Timeout and KeepAlive settings of the client.
func WithDialer(dialer *net.Dialer) func(*Client) error {
return func(c *Client) error {
if transport, ok := c.client.Transport.(*http.Transport); ok {
transport.DialContext = dialer.DialContext
return nil
}
return errors.Errorf("cannot apply dialer to transport: %T", c.client.Transport)
}
}
// WithVersion overrides the client version with the specified one
func WithVersion(version string) func(*Client) error {
return func(c *Client) error {
c.version = version
return nil
}
}
// WithHost overrides the client host with the specified one.
func WithHost(host string) func(*Client) error {
return func(c *Client) error {
hostURL, err := ParseHostURL(host)
if err != nil {
return err
}
c.host = host
c.proto = hostURL.Scheme
c.addr = hostURL.Host
c.basePath = hostURL.Path
if transport, ok := c.client.Transport.(*http.Transport); ok {
return sockets.ConfigureTransport(transport, c.proto, c.addr)
}
return errors.Errorf("cannot apply host to transport: %T", c.client.Transport)
}
}
// WithHTTPClient overrides the client http client with the specified one
func WithHTTPClient(client *http.Client) func(*Client) error {
return func(c *Client) error {
if client != nil {
c.client = client
}
return nil
}
}
// WithHTTPHeaders overrides the client default http headers
func WithHTTPHeaders(headers map[string]string) func(*Client) error {
return func(c *Client) error {
c.customHTTPHeaders = headers
return nil
}
}
// NewClientWithOpts initializes a new API client with default values. It takes functors
// to modify values when creating it, like `NewClientWithOpts(WithVersion(…))`
// It also initializes the custom http headers to add to each request.
//
// It won't send any version information if the version number is empty. It is
// highly recommended that you set a version or your client may break if the
// server is upgraded.
func NewClientWithOpts(ops ...func(*Client) error) (*Client, error) {
client, err := defaultHTTPClient(DefaultDockerHost)
if err != nil { if err != nil {
return nil, err return nil, err
} }
c := &Client{
host: DefaultDockerHost,
version: api.DefaultVersion,
scheme: "http",
client: client,
proto: defaultProto,
addr: defaultAddr,
}
for _, op := range ops { client = &http.Client{
if err := op(c); err != nil { Transport: &http.Transport{
return nil, err TLSClientConfig: tlsc,
},
} }
} }
if _, ok := c.client.Transport.(http.RoundTripper); !ok { host := os.Getenv("DOCKER_HOST")
return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", c.client.Transport) if host == "" {
host = DefaultDockerHost
} }
tlsConfig := resolveTLSConfig(c.client.Transport) version := os.Getenv("DOCKER_API_VERSION")
if tlsConfig != nil { if version == "" {
// TODO(stevvooe): This isn't really the right way to write clients in Go. version = api.DefaultVersion
// `NewClient` should probably only take an `*http.Client` and work from there.
// Unfortunately, the model of having a host-ish/url-thingy as the connection
// string has us confusing protocol and transport layers. We continue doing
// this to avoid breaking existing clients but this should be addressed.
c.scheme = "https"
} }
return c, nil cli, err := NewClient(host, version, client, nil)
}
func defaultHTTPClient(host string) (*http.Client, error) {
url, err := ParseHostURL(host)
if err != nil { if err != nil {
return nil, err return cli, err
} }
transport := new(http.Transport) if os.Getenv("DOCKER_API_VERSION") != "" {
sockets.ConfigureTransport(transport, url.Scheme, url.Host) cli.manualOverride = true
return &http.Client{ }
Transport: transport, return cli, nil
CheckRedirect: CheckRedirect,
}, nil
} }
// NewClient initializes a new API client for the given host and API version. // NewClient initializes a new API client for the given host and API version.
@@ -290,16 +133,57 @@ func defaultHTTPClient(host string) (*http.Client, error) {
// It won't send any version information if the version number is empty. It is // It won't send any version information if the version number is empty. It is
// highly recommended that you set a version or your client may break if the // highly recommended that you set a version or your client may break if the
// server is upgraded. // server is upgraded.
// Deprecated: use NewClientWithOpts
func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) { func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) {
return NewClientWithOpts(WithHost(host), WithVersion(version), WithHTTPClient(client), WithHTTPHeaders(httpHeaders)) proto, addr, basePath, err := ParseHost(host)
if err != nil {
return nil, err
}
if client != nil {
if _, ok := client.Transport.(*http.Transport); !ok {
return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", client.Transport)
}
} else {
transport := new(http.Transport)
sockets.ConfigureTransport(transport, proto, addr)
client = &http.Client{
Transport: transport,
}
}
scheme := "http"
tlsConfig := resolveTLSConfig(client.Transport)
if tlsConfig != nil {
// TODO(stevvooe): This isn't really the right way to write clients in Go.
// `NewClient` should probably only take an `*http.Client` and work from there.
// Unfortunately, the model of having a host-ish/url-thingy as the connection
// string has us confusing protocol and transport layers. We continue doing
// this to avoid breaking existing clients but this should be addressed.
scheme = "https"
}
return &Client{
scheme: scheme,
host: host,
proto: proto,
addr: addr,
basePath: basePath,
client: client,
version: version,
customHTTPHeaders: httpHeaders,
}, nil
} }
// Close the transport used by the client // Close ensures that transport.Client is closed
// especially needed while using NewClient with *http.Client = nil
// for example
// client.NewClient("unix:///var/run/docker.sock", nil, "v1.18", map[string]string{"User-Agent": "engine-api-cli-1.0"})
func (cli *Client) Close() error { func (cli *Client) Close() error {
if t, ok := cli.client.Transport.(*http.Transport); ok { if t, ok := cli.client.Transport.(*http.Transport); ok {
t.CloseIdleConnections() t.CloseIdleConnections()
} }
return nil return nil
} }
@@ -309,64 +193,42 @@ func (cli *Client) getAPIPath(p string, query url.Values) string {
var apiPath string var apiPath string
if cli.version != "" { if cli.version != "" {
v := strings.TrimPrefix(cli.version, "v") v := strings.TrimPrefix(cli.version, "v")
apiPath = path.Join(cli.basePath, "/v"+v, p) apiPath = fmt.Sprintf("%s/v%s%s", cli.basePath, v, p)
} else { } else {
apiPath = path.Join(cli.basePath, p) apiPath = fmt.Sprintf("%s%s", cli.basePath, p)
} }
return (&url.URL{Path: apiPath, RawQuery: query.Encode()}).String()
u := &url.URL{
Path: apiPath,
}
if len(query) > 0 {
u.RawQuery = query.Encode()
}
return u.String()
} }
// ClientVersion returns the API version used by this client. // ClientVersion returns the version string associated with this
// instance of the Client. Note that this value can be changed
// via the DOCKER_API_VERSION env var.
// This operation doesn't acquire a mutex.
func (cli *Client) ClientVersion() string { func (cli *Client) ClientVersion() string {
return cli.version return cli.version
} }
// NegotiateAPIVersion queries the API and updates the version to match the // UpdateClientVersion updates the version string associated with this
// API version. Any errors are silently ignored. // instance of the Client. This operation doesn't acquire a mutex.
func (cli *Client) NegotiateAPIVersion(ctx context.Context) { func (cli *Client) UpdateClientVersion(v string) {
ping, _ := cli.Ping(ctx) if !cli.manualOverride {
cli.NegotiateAPIVersionPing(ping) cli.version = v
}
// NegotiateAPIVersionPing updates the client version to match the Ping.APIVersion
// if the ping version is less than the default version.
func (cli *Client) NegotiateAPIVersionPing(p types.Ping) {
if cli.manualOverride {
return
} }
// try the latest version before versioning headers existed
if p.APIVersion == "" {
p.APIVersion = "1.24"
}
// if the client is not initialized with a version, start with the latest supported version
if cli.version == "" {
cli.version = api.DefaultVersion
}
// if server version is lower than the client version, downgrade
if versions.LessThan(p.APIVersion, cli.version) {
cli.version = p.APIVersion
}
} }
// DaemonHost returns the host address used by the client // ParseHost verifies that the given host strings is valid.
func (cli *Client) DaemonHost() string { func ParseHost(host string) (string, string, string, error) {
return cli.host
}
// HTTPClient returns a copy of the HTTP client bound to the server
func (cli *Client) HTTPClient() *http.Client {
return &*cli.client
}
// ParseHostURL parses a url string, validates the string is a host url, and
// returns the parsed URL
func ParseHostURL(host string) (*url.URL, error) {
protoAddrParts := strings.SplitN(host, "://", 2) protoAddrParts := strings.SplitN(host, "://", 2)
if len(protoAddrParts) == 1 { if len(protoAddrParts) == 1 {
return nil, fmt.Errorf("unable to parse docker host `%s`", host) return "", "", "", fmt.Errorf("unable to parse docker host `%s`", host)
} }
var basePath string var basePath string
@@ -374,19 +236,16 @@ func ParseHostURL(host string) (*url.URL, error) {
if proto == "tcp" { if proto == "tcp" {
parsed, err := url.Parse("tcp://" + addr) parsed, err := url.Parse("tcp://" + addr)
if err != nil { if err != nil {
return nil, err return "", "", "", err
} }
addr = parsed.Host addr = parsed.Host
basePath = parsed.Path basePath = parsed.Path
} }
return &url.URL{ return proto, addr, basePath, nil
Scheme: proto,
Host: addr,
Path: basePath,
}, nil
} }
// CustomHTTPHeaders returns the custom http headers stored by the client. // CustomHTTPHeaders returns the custom http headers associated with this
// instance of the Client. This operation doesn't acquire a mutex.
func (cli *Client) CustomHTTPHeaders() map[string]string { func (cli *Client) CustomHTTPHeaders() map[string]string {
m := make(map[string]string) m := make(map[string]string)
for k, v := range cli.customHTTPHeaders { for k, v := range cli.customHTTPHeaders {
@@ -395,8 +254,8 @@ func (cli *Client) CustomHTTPHeaders() map[string]string {
return m return m
} }
// SetCustomHTTPHeaders that will be set on every HTTP request made by the client. // SetCustomHTTPHeaders updates the custom http headers associated with this
// Deprecated: use WithHTTPHeaders when creating the client. // instance of the Client. This operation doesn't acquire a mutex.
func (cli *Client) SetCustomHTTPHeaders(headers map[string]string) { func (cli *Client) SetCustomHTTPHeaders(headers map[string]string) {
cli.customHTTPHeaders = headers cli.customHTTPHeaders = headers
} }

View File

@@ -1,9 +1,6 @@
// +build linux freebsd openbsd darwin // +build linux freebsd solaris openbsd darwin
package client // import "github.com/docker/docker/client" package client
// DefaultDockerHost defines os specific default if DOCKER_HOST is unset // DefaultDockerHost defines os specific default if DOCKER_HOST is unset
const DefaultDockerHost = "unix:///var/run/docker.sock" const DefaultDockerHost = "unix:///var/run/docker.sock"
const defaultProto = "unix"
const defaultAddr = "/var/run/docker.sock"

View File

@@ -1,7 +1,4 @@
package client // import "github.com/docker/docker/client" package client
// DefaultDockerHost defines os specific default if DOCKER_HOST is unset // DefaultDockerHost defines os specific default if DOCKER_HOST is unset
const DefaultDockerHost = "npipe:////./pipe/docker_engine" const DefaultDockerHost = "npipe:////./pipe/docker_engine"
const defaultProto = "npipe"
const defaultAddr = "//./pipe/docker_engine"

View File

@@ -1,25 +0,0 @@
package client // import "github.com/docker/docker/client"
import (
"context"
"encoding/json"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
)
// ConfigCreate creates a new Config.
func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
var response types.ConfigCreateResponse
if err := cli.NewVersionError("1.30", "config create"); err != nil {
return response, err
}
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}

View File

@@ -1,36 +0,0 @@
package client // import "github.com/docker/docker/client"
import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"github.com/docker/docker/api/types/swarm"
)
// ConfigInspectWithRaw returns the config information with raw data
func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.Config, []byte, error) {
if id == "" {
return swarm.Config{}, nil, objectNotFoundError{object: "config", id: id}
}
if err := cli.NewVersionError("1.30", "config inspect"); err != nil {
return swarm.Config{}, nil, err
}
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
if err != nil {
return swarm.Config{}, nil, wrapResponseError(err, resp, "config", id)
}
defer ensureReaderClosed(resp)
body, err := ioutil.ReadAll(resp.body)
if err != nil {
return swarm.Config{}, nil, err
}
var config swarm.Config
rdr := bytes.NewReader(body)
err = json.NewDecoder(rdr).Decode(&config)
return config, body, err
}

View File

@@ -1,38 +0,0 @@
package client // import "github.com/docker/docker/client"
import (
"context"
"encoding/json"
"net/url"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
)
// ConfigList returns the list of configs.
func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
if err := cli.NewVersionError("1.30", "config list"); err != nil {
return nil, err
}
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/configs", query, nil)
if err != nil {
return nil, err
}
var configs []swarm.Config
err = json.NewDecoder(resp.body).Decode(&configs)
ensureReaderClosed(resp)
return configs, err
}

View File

@@ -1,13 +0,0 @@
package client // import "github.com/docker/docker/client"
import "context"
// ConfigRemove removes a Config.
func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
if err := cli.NewVersionError("1.30", "config remove"); err != nil {
return err
}
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
ensureReaderClosed(resp)
return wrapResponseError(err, resp, "config", id)
}

View File

@@ -1,21 +0,0 @@
package client // import "github.com/docker/docker/client"
import (
"context"
"net/url"
"strconv"
"github.com/docker/docker/api/types/swarm"
)
// ConfigUpdate attempts to update a Config
func (cli *Client) ConfigUpdate(ctx context.Context, id string, version swarm.Version, config swarm.ConfigSpec) error {
if err := cli.NewVersionError("1.30", "config update"); err != nil {
return err
}
query := url.Values{}
query.Set("version", strconv.FormatUint(version.Index, 10))
resp, err := cli.post(ctx, "/configs/"+id+"/update", query, config, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,36 +1,16 @@
package client // import "github.com/docker/docker/client" package client
import ( import (
"context"
"net/url" "net/url"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"golang.org/x/net/context"
) )
// ContainerAttach attaches a connection to a container in the server. // ContainerAttach attaches a connection to a container in the server.
// It returns a types.HijackedConnection with the hijacked connection // It returns a types.HijackedConnection with the hijacked connection
// and the a reader to get output. It's up to the called to close // and the a reader to get output. It's up to the called to close
// the hijacked connection by calling types.HijackedResponse.Close. // the hijacked connection by calling types.HijackedResponse.Close.
//
// The stream format on the response will be in one of two formats:
//
// If the container is using a TTY, there is only a single stream (stdout), and
// data is copied directly from the container output stream, no extra
// multiplexing or headers.
//
// If the container is *not* using a TTY, streams for stdout and stderr are
// multiplexed.
// The format of the multiplexed stream is as follows:
//
// [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT}
//
// STREAM_TYPE can be 1 for stdout and 2 for stderr
//
// SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded as big endian.
// This is the size of OUTPUT.
//
// You can use github.com/docker/docker/pkg/stdcopy.StdCopy to demultiplex this
// stream.
func (cli *Client) ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error) { func (cli *Client) ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error) {
query := url.Values{} query := url.Values{}
if options.Stream { if options.Stream {

View File

@@ -1,13 +1,13 @@
package client // import "github.com/docker/docker/client" package client
import ( import (
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"net/url" "net/url"
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"golang.org/x/net/context"
) )
// ContainerCommit applies changes into a container and creates a new tagged image. // ContainerCommit applies changes into a container and creates a new tagged image.
@@ -39,7 +39,7 @@ func (cli *Client) ContainerCommit(ctx context.Context, container string, option
for _, change := range options.Changes { for _, change := range options.Changes {
query.Add("changes", change) query.Add("changes", change)
} }
if !options.Pause { if options.Pause != true {
query.Set("pause", "0") query.Set("pause", "0")
} }

View File

@@ -1,7 +1,6 @@
package client // import "github.com/docker/docker/client" package client
import ( import (
"context"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
@@ -11,6 +10,8 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"golang.org/x/net/context"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
) )
@@ -19,34 +20,29 @@ func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path stri
query := url.Values{} query := url.Values{}
query.Set("path", filepath.ToSlash(path)) // Normalize the paths used in the API. query.Set("path", filepath.ToSlash(path)) // Normalize the paths used in the API.
urlStr := "/containers/" + containerID + "/archive" urlStr := fmt.Sprintf("/containers/%s/archive", containerID)
response, err := cli.head(ctx, urlStr, query, nil) response, err := cli.head(ctx, urlStr, query, nil)
if err != nil { if err != nil {
return types.ContainerPathStat{}, wrapResponseError(err, response, "container:path", containerID+":"+path) return types.ContainerPathStat{}, err
} }
defer ensureReaderClosed(response) defer ensureReaderClosed(response)
return getContainerPathStatFromHeader(response.header) return getContainerPathStatFromHeader(response.header)
} }
// CopyToContainer copies content into the container filesystem. // CopyToContainer copies content into the container filesystem.
// Note that `content` must be a Reader for a TAR archive func (cli *Client) CopyToContainer(ctx context.Context, container, path string, content io.Reader, options types.CopyToContainerOptions) error {
func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath string, content io.Reader, options types.CopyToContainerOptions) error {
query := url.Values{} query := url.Values{}
query.Set("path", filepath.ToSlash(dstPath)) // Normalize the paths used in the API. query.Set("path", filepath.ToSlash(path)) // Normalize the paths used in the API.
// Do not allow for an existing directory to be overwritten by a non-directory and vice versa. // Do not allow for an existing directory to be overwritten by a non-directory and vice versa.
if !options.AllowOverwriteDirWithFile { if !options.AllowOverwriteDirWithFile {
query.Set("noOverwriteDirNonDir", "true") query.Set("noOverwriteDirNonDir", "true")
} }
if options.CopyUIDGID { apiPath := fmt.Sprintf("/containers/%s/archive", container)
query.Set("copyUIDGID", "true")
}
apiPath := "/containers/" + containerID + "/archive"
response, err := cli.putRaw(ctx, apiPath, query, content, nil) response, err := cli.putRaw(ctx, apiPath, query, content, nil)
if err != nil { if err != nil {
return wrapResponseError(err, response, "container:path", containerID+":"+dstPath) return err
} }
defer ensureReaderClosed(response) defer ensureReaderClosed(response)
@@ -58,15 +54,15 @@ func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath str
} }
// CopyFromContainer gets the content from the container and returns it as a Reader // CopyFromContainer gets the content from the container and returns it as a Reader
// for a TAR archive to manipulate it in the host. It's up to the caller to close the reader. // to manipulate it in the host. It's up to the caller to close the reader.
func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) { func (cli *Client) CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
query := make(url.Values, 1) query := make(url.Values, 1)
query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API. query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API.
apiPath := "/containers/" + containerID + "/archive" apiPath := fmt.Sprintf("/containers/%s/archive", container)
response, err := cli.get(ctx, apiPath, query, nil) response, err := cli.get(ctx, apiPath, query, nil)
if err != nil { if err != nil {
return nil, types.ContainerPathStat{}, wrapResponseError(err, response, "container:path", containerID+":"+srcPath) return nil, types.ContainerPathStat{}, err
} }
if response.statusCode != http.StatusOK { if response.statusCode != http.StatusOK {

View File

@@ -1,7 +1,6 @@
package client // import "github.com/docker/docker/client" package client
import ( import (
"context"
"encoding/json" "encoding/json"
"net/url" "net/url"
"strings" "strings"
@@ -9,6 +8,7 @@ import (
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/versions" "github.com/docker/docker/api/types/versions"
"golang.org/x/net/context"
) )
type configWrapper struct { type configWrapper struct {
@@ -45,7 +45,7 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
serverResp, err := cli.post(ctx, "/containers/create", query, body, nil) serverResp, err := cli.post(ctx, "/containers/create", query, body, nil)
if err != nil { if err != nil {
if serverResp.statusCode == 404 && strings.Contains(err.Error(), "No such image") { if serverResp.statusCode == 404 && strings.Contains(err.Error(), "No such image") {
return response, objectNotFoundError{object: "image", id: config.Image} return response, imageNotFoundError{config.Image}
} }
return response, err return response, err
} }

View File

@@ -1,11 +1,11 @@
package client // import "github.com/docker/docker/client" package client
import ( import (
"context"
"encoding/json" "encoding/json"
"net/url" "net/url"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"golang.org/x/net/context"
) )
// ContainerDiff shows differences in a container filesystem since it was started. // ContainerDiff shows differences in a container filesystem since it was started.

View File

@@ -1,10 +1,10 @@
package client // import "github.com/docker/docker/client" package client
import ( import (
"context"
"encoding/json" "encoding/json"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"golang.org/x/net/context"
) )
// ContainerExecCreate creates a new exec configuration to run an exec process. // ContainerExecCreate creates a new exec configuration to run an exec process.
@@ -35,7 +35,7 @@ func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config
// It returns a types.HijackedConnection with the hijacked connection // It returns a types.HijackedConnection with the hijacked connection
// and the a reader to get output. It's up to the called to close // and the a reader to get output. It's up to the called to close
// the hijacked connection by calling types.HijackedResponse.Close. // the hijacked connection by calling types.HijackedResponse.Close.
func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) { func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config types.ExecConfig) (types.HijackedResponse, error) {
headers := map[string][]string{"Content-Type": {"application/json"}} headers := map[string][]string{"Content-Type": {"application/json"}}
return cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, config, headers) return cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, config, headers)
} }

Some files were not shown because too many files have changed in this diff Show More