mirror of
https://gitea.com/gitea/runner.git
synced 2026-11-04 14:35:32 +00:00
chore(deps): cleanup go.mod a little bit (#136)
* Upgrade docker to v19.03.7 * go mod vendor * golangci-lint 1.23.8
This commit is contained in:
1 parent
f46768cf90
commit
ca648a37c8
463 files changed
+67593
-38404
No files matched your search
+267
@@ -0,0 +1,267 @@
|
||||
package errcode
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrorCoder is the base interface for ErrorCode and Error allowing
|
||||
// users of each to just call ErrorCode to get the real ID of each
|
||||
type ErrorCoder interface {
|
||||
ErrorCode() ErrorCode
|
||||
}
|
||||
|
||||
// ErrorCode represents the error type. The errors are serialized via strings
|
||||
// and the integer format may change and should *never* be exported.
|
||||
type ErrorCode int
|
||||
|
||||
var _ error = ErrorCode(0)
|
||||
|
||||
// ErrorCode just returns itself
|
||||
func (ec ErrorCode) ErrorCode() ErrorCode {
|
||||
return ec
|
||||
}
|
||||
|
||||
// Error returns the ID/Value
|
||||
func (ec ErrorCode) Error() string {
|
||||
// NOTE(stevvooe): Cannot use message here since it may have unpopulated args.
|
||||
return strings.ToLower(strings.Replace(ec.String(), "_", " ", -1))
|
||||
}
|
||||
|
||||
// Descriptor returns the descriptor for the error code.
|
||||
func (ec ErrorCode) Descriptor() ErrorDescriptor {
|
||||
d, ok := errorCodeToDescriptors[ec]
|
||||
|
||||
if !ok {
|
||||
return ErrorCodeUnknown.Descriptor()
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// String returns the canonical identifier for this error code.
|
||||
func (ec ErrorCode) String() string {
|
||||
return ec.Descriptor().Value
|
||||
}
|
||||
|
||||
// Message returned the human-readable error message for this error code.
|
||||
func (ec ErrorCode) Message() string {
|
||||
return ec.Descriptor().Message
|
||||
}
|
||||
|
||||
// MarshalText encodes the receiver into UTF-8-encoded text and returns the
|
||||
// result.
|
||||
func (ec ErrorCode) MarshalText() (text []byte, err error) {
|
||||
return []byte(ec.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText decodes the form generated by MarshalText.
|
||||
func (ec *ErrorCode) UnmarshalText(text []byte) error {
|
||||
desc, ok := idToDescriptors[string(text)]
|
||||
|
||||
if !ok {
|
||||
desc = ErrorCodeUnknown.Descriptor()
|
||||
}
|
||||
|
||||
*ec = desc.Code
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithMessage creates a new Error struct based on the passed-in info and
|
||||
// overrides the Message property.
|
||||
func (ec ErrorCode) WithMessage(message string) Error {
|
||||
return Error{
|
||||
Code: ec,
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// WithDetail creates a new Error struct based on the passed-in info and
|
||||
// set the Detail property appropriately
|
||||
func (ec ErrorCode) WithDetail(detail interface{}) Error {
|
||||
return Error{
|
||||
Code: ec,
|
||||
Message: ec.Message(),
|
||||
}.WithDetail(detail)
|
||||
}
|
||||
|
||||
// WithArgs creates a new Error struct and sets the Args slice
|
||||
func (ec ErrorCode) WithArgs(args ...interface{}) Error {
|
||||
return Error{
|
||||
Code: ec,
|
||||
Message: ec.Message(),
|
||||
}.WithArgs(args...)
|
||||
}
|
||||
|
||||
// Error provides a wrapper around ErrorCode with extra Details provided.
|
||||
type Error struct {
|
||||
Code ErrorCode `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Detail interface{} `json:"detail,omitempty"`
|
||||
|
||||
// TODO(duglin): See if we need an "args" property so we can do the
|
||||
// variable substitution right before showing the message to the user
|
||||
}
|
||||
|
||||
var _ error = Error{}
|
||||
|
||||
// ErrorCode returns the ID/Value of this Error
|
||||
func (e Error) ErrorCode() ErrorCode {
|
||||
return e.Code
|
||||
}
|
||||
|
||||
// Error returns a human readable representation of the error.
|
||||
func (e Error) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Code.Error(), e.Message)
|
||||
}
|
||||
|
||||
// WithDetail will return a new Error, based on the current one, but with
|
||||
// some Detail info added
|
||||
func (e Error) WithDetail(detail interface{}) Error {
|
||||
return Error{
|
||||
Code: e.Code,
|
||||
Message: e.Message,
|
||||
Detail: detail,
|
||||
}
|
||||
}
|
||||
|
||||
// WithArgs uses the passed-in list of interface{} as the substitution
|
||||
// variables in the Error's Message string, but returns a new Error
|
||||
func (e Error) WithArgs(args ...interface{}) Error {
|
||||
return Error{
|
||||
Code: e.Code,
|
||||
Message: fmt.Sprintf(e.Code.Message(), args...),
|
||||
Detail: e.Detail,
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorDescriptor provides relevant information about a given error code.
|
||||
type ErrorDescriptor struct {
|
||||
// Code is the error code that this descriptor describes.
|
||||
Code ErrorCode
|
||||
|
||||
// Value provides a unique, string key, often captilized with
|
||||
// underscores, to identify the error code. This value is used as the
|
||||
// keyed value when serializing api errors.
|
||||
Value string
|
||||
|
||||
// Message is a short, human readable decription of the error condition
|
||||
// included in API responses.
|
||||
Message string
|
||||
|
||||
// Description provides a complete account of the errors purpose, suitable
|
||||
// for use in documentation.
|
||||
Description string
|
||||
|
||||
// HTTPStatusCode provides the http status code that is associated with
|
||||
// this error condition.
|
||||
HTTPStatusCode int
|
||||
}
|
||||
|
||||
// ParseErrorCode returns the value by the string error code.
|
||||
// `ErrorCodeUnknown` will be returned if the error is not known.
|
||||
func ParseErrorCode(value string) ErrorCode {
|
||||
ed, ok := idToDescriptors[value]
|
||||
if ok {
|
||||
return ed.Code
|
||||
}
|
||||
|
||||
return ErrorCodeUnknown
|
||||
}
|
||||
|
||||
// Errors provides the envelope for multiple errors and a few sugar methods
|
||||
// for use within the application.
|
||||
type Errors []error
|
||||
|
||||
var _ error = Errors{}
|
||||
|
||||
func (errs Errors) Error() string {
|
||||
switch len(errs) {
|
||||
case 0:
|
||||
return "<nil>"
|
||||
case 1:
|
||||
return errs[0].Error()
|
||||
default:
|
||||
msg := "errors:\n"
|
||||
for _, err := range errs {
|
||||
msg += err.Error() + "\n"
|
||||
}
|
||||
return msg
|
||||
}
|
||||
}
|
||||
|
||||
// Len returns the current number of errors.
|
||||
func (errs Errors) Len() int {
|
||||
return len(errs)
|
||||
}
|
||||
|
||||
// MarshalJSON converts slice of error, ErrorCode or Error into a
|
||||
// slice of Error - then serializes
|
||||
func (errs Errors) MarshalJSON() ([]byte, error) {
|
||||
var tmpErrs struct {
|
||||
Errors []Error `json:"errors,omitempty"`
|
||||
}
|
||||
|
||||
for _, daErr := range errs {
|
||||
var err Error
|
||||
|
||||
switch daErr.(type) {
|
||||
case ErrorCode:
|
||||
err = daErr.(ErrorCode).WithDetail(nil)
|
||||
case Error:
|
||||
err = daErr.(Error)
|
||||
default:
|
||||
err = ErrorCodeUnknown.WithDetail(daErr)
|
||||
|
||||
}
|
||||
|
||||
// If the Error struct was setup and they forgot to set the
|
||||
// Message field (meaning its "") then grab it from the ErrCode
|
||||
msg := err.Message
|
||||
if msg == "" {
|
||||
msg = err.Code.Message()
|
||||
}
|
||||
|
||||
tmpErrs.Errors = append(tmpErrs.Errors, Error{
|
||||
Code: err.Code,
|
||||
Message: msg,
|
||||
Detail: err.Detail,
|
||||
})
|
||||
}
|
||||
|
||||
return json.Marshal(tmpErrs)
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes []Error and then converts it into slice of
|
||||
// Error or ErrorCode
|
||||
func (errs *Errors) UnmarshalJSON(data []byte) error {
|
||||
var tmpErrs struct {
|
||||
Errors []Error
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &tmpErrs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var newErrs Errors
|
||||
for _, daErr := range tmpErrs.Errors {
|
||||
// If Message is empty or exactly matches the Code's message string
|
||||
// then just use the Code, no need for a full Error struct
|
||||
if daErr.Detail == nil && (daErr.Message == "" || daErr.Message == daErr.Code.Message()) {
|
||||
// Error's w/o details get converted to ErrorCode
|
||||
newErrs = append(newErrs, daErr.Code)
|
||||
} else {
|
||||
// Error's w/ details are untouched
|
||||
newErrs = append(newErrs, Error{
|
||||
Code: daErr.Code,
|
||||
Message: daErr.Message,
|
||||
Detail: daErr.Detail,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
*errs = newErrs
|
||||
return nil
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package errcode
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ServeJSON attempts to serve the errcode in a JSON envelope. It marshals err
|
||||
// and sets the content-type header to 'application/json'. It will handle
|
||||
// ErrorCoder and Errors, and if necessary will create an envelope.
|
||||
func ServeJSON(w http.ResponseWriter, err error) error {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
var sc int
|
||||
|
||||
switch errs := err.(type) {
|
||||
case Errors:
|
||||
if len(errs) < 1 {
|
||||
break
|
||||
}
|
||||
|
||||
if err, ok := errs[0].(ErrorCoder); ok {
|
||||
sc = err.ErrorCode().Descriptor().HTTPStatusCode
|
||||
}
|
||||
case ErrorCoder:
|
||||
sc = errs.ErrorCode().Descriptor().HTTPStatusCode
|
||||
err = Errors{err} // create an envelope.
|
||||
default:
|
||||
// We just have an unhandled error type, so just place in an envelope
|
||||
// and move along.
|
||||
err = Errors{err}
|
||||
}
|
||||
|
||||
if sc == 0 {
|
||||
sc = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
w.WriteHeader(sc)
|
||||
|
||||
return json.NewEncoder(w).Encode(err)
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
package errcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{}
|
||||
idToDescriptors = map[string]ErrorDescriptor{}
|
||||
groupToDescriptors = map[string][]ErrorDescriptor{}
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrorCodeUnknown is a generic error that can be used as a last
|
||||
// resort if there is no situation-specific error message that can be used
|
||||
ErrorCodeUnknown = Register("errcode", ErrorDescriptor{
|
||||
Value: "UNKNOWN",
|
||||
Message: "unknown error",
|
||||
Description: `Generic error returned when the error does not have an
|
||||
API classification.`,
|
||||
HTTPStatusCode: http.StatusInternalServerError,
|
||||
})
|
||||
|
||||
// ErrorCodeUnsupported is returned when an operation is not supported.
|
||||
ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{
|
||||
Value: "UNSUPPORTED",
|
||||
Message: "The operation is unsupported.",
|
||||
Description: `The operation was unsupported due to a missing
|
||||
implementation or invalid set of parameters.`,
|
||||
HTTPStatusCode: http.StatusMethodNotAllowed,
|
||||
})
|
||||
|
||||
// ErrorCodeUnauthorized is returned if a request requires
|
||||
// authentication.
|
||||
ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{
|
||||
Value: "UNAUTHORIZED",
|
||||
Message: "authentication required",
|
||||
Description: `The access controller was unable to authenticate
|
||||
the client. Often this will be accompanied by a
|
||||
Www-Authenticate HTTP response header indicating how to
|
||||
authenticate.`,
|
||||
HTTPStatusCode: http.StatusUnauthorized,
|
||||
})
|
||||
|
||||
// ErrorCodeDenied is returned if a client does not have sufficient
|
||||
// permission to perform an action.
|
||||
ErrorCodeDenied = Register("errcode", ErrorDescriptor{
|
||||
Value: "DENIED",
|
||||
Message: "requested access to the resource is denied",
|
||||
Description: `The access controller denied access for the
|
||||
operation on a resource.`,
|
||||
HTTPStatusCode: http.StatusForbidden,
|
||||
})
|
||||
|
||||
// ErrorCodeUnavailable provides a common error to report unavailability
|
||||
// of a service or endpoint.
|
||||
ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{
|
||||
Value: "UNAVAILABLE",
|
||||
Message: "service unavailable",
|
||||
Description: "Returned when a service is not available",
|
||||
HTTPStatusCode: http.StatusServiceUnavailable,
|
||||
})
|
||||
|
||||
// ErrorCodeTooManyRequests is returned if a client attempts too many
|
||||
// times to contact a service endpoint.
|
||||
ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{
|
||||
Value: "TOOMANYREQUESTS",
|
||||
Message: "too many requests",
|
||||
Description: `Returned when a client attempts to contact a
|
||||
service too many times`,
|
||||
HTTPStatusCode: http.StatusTooManyRequests,
|
||||
})
|
||||
)
|
||||
|
||||
var nextCode = 1000
|
||||
var registerLock sync.Mutex
|
||||
|
||||
// Register will make the passed-in error known to the environment and
|
||||
// return a new ErrorCode
|
||||
func Register(group string, descriptor ErrorDescriptor) ErrorCode {
|
||||
registerLock.Lock()
|
||||
defer registerLock.Unlock()
|
||||
|
||||
descriptor.Code = ErrorCode(nextCode)
|
||||
|
||||
if _, ok := idToDescriptors[descriptor.Value]; ok {
|
||||
panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value))
|
||||
}
|
||||
if _, ok := errorCodeToDescriptors[descriptor.Code]; ok {
|
||||
panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code))
|
||||
}
|
||||
|
||||
groupToDescriptors[group] = append(groupToDescriptors[group], descriptor)
|
||||
errorCodeToDescriptors[descriptor.Code] = descriptor
|
||||
idToDescriptors[descriptor.Value] = descriptor
|
||||
|
||||
nextCode++
|
||||
return descriptor.Code
|
||||
}
|
||||
|
||||
type byValue []ErrorDescriptor
|
||||
|
||||
func (a byValue) Len() int { return len(a) }
|
||||
func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value }
|
||||
|
||||
// GetGroupNames returns the list of Error group names that are registered
|
||||
func GetGroupNames() []string {
|
||||
keys := []string{}
|
||||
|
||||
for k := range groupToDescriptors {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
// GetErrorCodeGroup returns the named group of error descriptors
|
||||
func GetErrorCodeGroup(name string) []ErrorDescriptor {
|
||||
desc := groupToDescriptors[name]
|
||||
sort.Sort(byValue(desc))
|
||||
return desc
|
||||
}
|
||||
|
||||
// GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are
|
||||
// registered, irrespective of what group they're in
|
||||
func GetErrorAllDescriptors() []ErrorDescriptor {
|
||||
result := []ErrorDescriptor{}
|
||||
|
||||
for _, group := range GetGroupNames() {
|
||||
result = append(result, GetErrorCodeGroup(group)...)
|
||||
}
|
||||
sort.Sort(byValue(result))
|
||||
return result
|
||||
}
|
||||
+108
-12
@@ -44,7 +44,7 @@ Ajey Charantimath <[email protected]>
|
||||
ajneu <[email protected]>
|
||||
Akash Gupta <[email protected]>
|
||||
Akihiro Matsushima <[email protected]>
|
||||
Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
|
||||
Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
|
||||
Akim Demaille <[email protected]>
|
||||
Akira Koyasu <[email protected]>
|
||||
Akshay Karle <[email protected]>
|
||||
@@ -81,6 +81,7 @@ Alexandre Garnier <[email protected]>
|
||||
Alexandre González <[email protected]>
|
||||
Alexandre Jomin <[email protected]>
|
||||
Alexandru Sfirlogea <[email protected]>
|
||||
Alexei Margasov <[email protected]>
|
||||
Alexey Guskov <[email protected]>
|
||||
Alexey Kotlyarov <[email protected]>
|
||||
Alexey Shamrin <[email protected]>
|
||||
@@ -118,6 +119,7 @@ Andreas Köhler <[email protected]>
|
||||
Andreas Savvides <[email protected]>
|
||||
Andreas Tiefenthaler <[email protected]>
|
||||
Andrei Gherzan <[email protected]>
|
||||
Andrei Vagin <[email protected]>
|
||||
Andrew C. Bodine <[email protected]>
|
||||
Andrew Clay Shafer <[email protected]>
|
||||
Andrew Duckworth <[email protected]>
|
||||
@@ -137,6 +139,7 @@ Andrew Po <[email protected]>
|
||||
Andrew Weiss <[email protected]>
|
||||
Andrew Williams <[email protected]>
|
||||
Andrews Medina <[email protected]>
|
||||
Andrey Kolomentsev <[email protected]>
|
||||
Andrey Petrov <[email protected]>
|
||||
Andrey Stolbovsky <[email protected]>
|
||||
André Martins <[email protected]>
|
||||
@@ -151,6 +154,7 @@ Andy Wilson <[email protected]>
|
||||
Anes Hasicic <[email protected]>
|
||||
Anil Belur <[email protected]>
|
||||
Anil Madhavapeddy <[email protected]>
|
||||
Ankit Jain <[email protected]>
|
||||
Ankush Agarwal <[email protected]>
|
||||
Anonmily <[email protected]>
|
||||
Anran Qiao <[email protected]>
|
||||
@@ -182,6 +186,7 @@ Asad Saeeduddin <[email protected]>
|
||||
Asbjørn Enge <[email protected]>
|
||||
averagehuman <[email protected]>
|
||||
Avi Das <[email protected]>
|
||||
Avi Kivity <[email protected]>
|
||||
Avi Miller <[email protected]>
|
||||
Avi Vaid <[email protected]>
|
||||
ayoshitake <[email protected]>
|
||||
@@ -195,23 +200,27 @@ bdevloed <[email protected]>
|
||||
Ben Bonnefoy <[email protected]>
|
||||
Ben Firshman <[email protected]>
|
||||
Ben Golub <[email protected]>
|
||||
Ben Gould <[email protected]>
|
||||
Ben Hall <[email protected]>
|
||||
Ben Sargent <[email protected]>
|
||||
Ben Severson <[email protected]>
|
||||
Ben Toews <[email protected]>
|
||||
Ben Wiklund <[email protected]>
|
||||
Benjamin Atkin <[email protected]>
|
||||
Benjamin Baker <[email protected]>
|
||||
Benjamin Boudreau <[email protected]>
|
||||
Benjamin Yolken <[email protected]>
|
||||
Benoit Chesneau <[email protected]>
|
||||
Bernerd Schaefer <[email protected]>
|
||||
Bernhard M. Wiedemann <[email protected]>
|
||||
Bert Goethals <[email protected]>
|
||||
Bevisy Zhang <[email protected]>
|
||||
Bharath Thiruveedula <[email protected]>
|
||||
Bhiraj Butala <[email protected]>
|
||||
Bhumika Bayani <[email protected]>
|
||||
Bilal Amarni <[email protected]>
|
||||
Bill Wang <[email protected]>
|
||||
Bily Zhang <[email protected]>
|
||||
Bin Liu <[email protected]>
|
||||
Bingshen Wang <[email protected]>
|
||||
Blake Geno <[email protected]>
|
||||
@@ -246,6 +255,7 @@ Brian Torres-Gil <[email protected]>
|
||||
Brian Trump <[email protected]>
|
||||
Brice Jaglin <[email protected]>
|
||||
Briehan Lombaard <[email protected]>
|
||||
Brielle Broder <[email protected]>
|
||||
Bruno Bigras <[email protected]>
|
||||
Bruno Binet <[email protected]>
|
||||
Bruno Gazzera <[email protected]>
|
||||
@@ -300,6 +310,7 @@ Chen Min <[email protected]>
|
||||
Chen Mingjie <[email protected]>
|
||||
Chen Qiu <[email protected]>
|
||||
Cheng-mean Liu <[email protected]>
|
||||
Chengfei Shang <[email protected]>
|
||||
Chengguang Xu <[email protected]>
|
||||
chenyuzhu <[email protected]>
|
||||
Chetan Birajdar <[email protected]>
|
||||
@@ -325,9 +336,11 @@ Chris Swan <[email protected]>
|
||||
Chris Telfer <[email protected]>
|
||||
Chris Wahl <[email protected]>
|
||||
Chris Weyl <[email protected]>
|
||||
Chris White <[email protected]>
|
||||
Christian Berendt <[email protected]>
|
||||
Christian Brauner <[email protected]>
|
||||
Christian Böhme <[email protected]>
|
||||
Christian Muehlhaeuser <[email protected]>
|
||||
Christian Persson <[email protected]>
|
||||
Christian Rotzoll <[email protected]>
|
||||
Christian Simon <[email protected]>
|
||||
@@ -350,6 +363,7 @@ Cody Roseborough <[email protected]>
|
||||
Coenraad Loubser <[email protected]>
|
||||
Colin Dunklau <[email protected]>
|
||||
Colin Hebert <[email protected]>
|
||||
Colin Panisset <[email protected]>
|
||||
Colin Rice <[email protected]>
|
||||
Colin Walters <[email protected]>
|
||||
Collin Guarino <[email protected]>
|
||||
@@ -385,6 +399,7 @@ Dan Levy <[email protected]>
|
||||
Dan McPherson <[email protected]>
|
||||
Dan Stine <[email protected]>
|
||||
Dan Williams <[email protected]>
|
||||
Dani Hodovic <[email protected]>
|
||||
Dani Louca <[email protected]>
|
||||
Daniel Antlinger <[email protected]>
|
||||
Daniel Dao <[email protected]>
|
||||
@@ -438,12 +453,14 @@ David Mackey <[email protected]>
|
||||
David Mat <[email protected]>
|
||||
David Mcanulty <[email protected]>
|
||||
David McKay <[email protected]>
|
||||
David P Hilton <[email protected]>
|
||||
David Pelaez <[email protected]>
|
||||
David R. Jenni <[email protected]>
|
||||
David Röthlisberger <[email protected]>
|
||||
David Sheets <[email protected]>
|
||||
David Sissitka <[email protected]>
|
||||
David Trott <[email protected]>
|
||||
David Wang <[email protected]>
|
||||
David Williamson <[email protected]>
|
||||
David Xia <[email protected]>
|
||||
David Young <[email protected]>
|
||||
@@ -451,8 +468,10 @@ Davide Ceretti <[email protected]>
|
||||
Dawn Chen <[email protected]>
|
||||
dbdd <[email protected]>
|
||||
dcylabs <[email protected]>
|
||||
Debayan De <[email protected]>
|
||||
Deborah Gertrude Digges <[email protected]>
|
||||
deed02392 <[email protected]>
|
||||
Deep Debroy <[email protected]>
|
||||
Deng Guangxing <[email protected]>
|
||||
Deni Bertovic <[email protected]>
|
||||
Denis Defreyne <[email protected]>
|
||||
@@ -477,6 +496,7 @@ Dieter Reuter <[email protected]>
|
||||
Dillon Dixon <[email protected]>
|
||||
Dima Stopel <[email protected]>
|
||||
Dimitri John Ledkov <[email protected]>
|
||||
Dimitris Mandalidis <[email protected]>
|
||||
Dimitris Rozakis <[email protected]>
|
||||
Dimitry Andric <[email protected]>
|
||||
Dinesh Subhraveti <[email protected]>
|
||||
@@ -490,6 +510,7 @@ Dmitri Shuralyov <[email protected]>
|
||||
Dmitry Demeshchuk <[email protected]>
|
||||
Dmitry Gusev <[email protected]>
|
||||
Dmitry Kononenko <[email protected]>
|
||||
Dmitry Sharshakov <[email protected]>
|
||||
Dmitry Shyshkin <[email protected]>
|
||||
Dmitry Smirnov <[email protected]>
|
||||
Dmitry V. Krivenok <[email protected]>
|
||||
@@ -503,6 +524,7 @@ Don Kjer <[email protected]>
|
||||
Don Spaulding <[email protected]>
|
||||
Donald Huang <[email protected]>
|
||||
Dong Chen <[email protected]>
|
||||
Donghwa Kim <[email protected]>
|
||||
Donovan Jones <[email protected]>
|
||||
Doron Podoleanu <[email protected]>
|
||||
Doug Davis <[email protected]>
|
||||
@@ -579,7 +601,9 @@ Ewa Czechowska <[email protected]>
|
||||
Eystein Måløy Stenberg <[email protected]>
|
||||
ezbercih <[email protected]>
|
||||
Ezra Silvera <[email protected]>
|
||||
Fabian Kramm <[email protected]>
|
||||
Fabian Lauer <[email protected]>
|
||||
Fabian Raetz <[email protected]>
|
||||
Fabiano Rosas <[email protected]>
|
||||
Fabio Falci <[email protected]>
|
||||
Fabio Kung <[email protected]>
|
||||
@@ -591,6 +615,7 @@ Faiz Khan <[email protected]>
|
||||
falmp <[email protected]>
|
||||
Fangming Fang <[email protected]>
|
||||
Fangyuan Gao <[email protected]>
|
||||
fanjiyun <[email protected]>
|
||||
Fareed Dudhia <[email protected]>
|
||||
Fathi Boudra <[email protected]>
|
||||
Federico Gimenez <[email protected]>
|
||||
@@ -621,6 +646,7 @@ Florin Patan <[email protected]>
|
||||
fonglh <[email protected]>
|
||||
Foysal Iqbal <[email protected]>
|
||||
Francesc Campoy <[email protected]>
|
||||
Francesco Mari <[email protected]>
|
||||
Francis Chuang <[email protected]>
|
||||
Francisco Carriedo <[email protected]>
|
||||
Francisco Souza <[email protected]>
|
||||
@@ -634,6 +660,7 @@ Frederik Loeffert <[email protected]>
|
||||
Frederik Nordahl Jul Sabroe <[email protected]>
|
||||
Freek Kalter <[email protected]>
|
||||
Frieder Bluemle <[email protected]>
|
||||
Fu JinLin <[email protected]>
|
||||
Félix Baylac-Jacqué <[email protected]>
|
||||
Félix Cantournet <[email protected]>
|
||||
Gabe Rosenhouse <[email protected]>
|
||||
@@ -653,6 +680,7 @@ Gaël PORTAY <[email protected]>
|
||||
Genki Takiuchi <[email protected]>
|
||||
GennadySpb <[email protected]>
|
||||
Geoffrey Bachelet <[email protected]>
|
||||
Geon Kim <[email protected]>
|
||||
George Kontridze <[email protected]>
|
||||
George MacRorie <[email protected]>
|
||||
George Xie <[email protected]>
|
||||
@@ -665,6 +693,7 @@ Ghislain Bourgeois <[email protected]>
|
||||
Giampaolo Mancini <[email protected]>
|
||||
Gianluca Borello <[email protected]>
|
||||
Gildas Cuisinier <[email protected]>
|
||||
Giovan Isa Musthofa <[email protected]>
|
||||
gissehel <[email protected]>
|
||||
Giuseppe Mazzotta <[email protected]>
|
||||
Gleb Fotengauer-Malinovskiy <[email protected]>
|
||||
@@ -676,6 +705,7 @@ Gopikannan Venugopalsamy <[email protected]>
|
||||
Gosuke Miyashita <[email protected]>
|
||||
Gou Rao <[email protected]>
|
||||
Govinda Fichtner <[email protected]>
|
||||
Grant Millar <[email protected]>
|
||||
Grant Reaber <[email protected]>
|
||||
Graydon Hoare <[email protected]>
|
||||
Greg Fausak <[email protected]>
|
||||
@@ -694,7 +724,9 @@ Guruprasad <[email protected]>
|
||||
Gustav Sinder <[email protected]>
|
||||
gwx296173 <[email protected]>
|
||||
Günter Zöchbauer <[email protected]>
|
||||
haikuoliu <[email protected]>
|
||||
Hakan Özler <[email protected]>
|
||||
Hamish Hutchings <[email protected]>
|
||||
Hans Kristian Flaatten <[email protected]>
|
||||
Hans Rødtang <[email protected]>
|
||||
Hao Shu Wei <[email protected]>
|
||||
@@ -702,6 +734,7 @@ Hao Zhang <[email protected]>
|
||||
Harald Albers <[email protected]>
|
||||
Harley Laue <[email protected]>
|
||||
Harold Cooper <[email protected]>
|
||||
Harrison Turton <[email protected]>
|
||||
Harry Zhang <[email protected]>
|
||||
Harshal Patil <[email protected]>
|
||||
Harshal Patil <[email protected]>
|
||||
@@ -713,6 +746,7 @@ Hector Castro <[email protected]>
|
||||
Helen Xie <[email protected]>
|
||||
Henning Sprang <[email protected]>
|
||||
Hiroshi Hatake <[email protected]>
|
||||
Hiroyuki Sasagawa <[email protected]>
|
||||
Hobofan <[email protected]>
|
||||
Hollie Teal <[email protected]>
|
||||
Hong Xu <[email protected]>
|
||||
@@ -735,6 +769,7 @@ Ian Bishop <[email protected]>
|
||||
Ian Bull <[email protected]>
|
||||
Ian Calvert <[email protected]>
|
||||
Ian Campbell <[email protected]>
|
||||
Ian Chen <[email protected]>
|
||||
Ian Lee <[email protected]>
|
||||
Ian Main <[email protected]>
|
||||
Ian Philpot <[email protected]>
|
||||
@@ -752,9 +787,11 @@ Ilya Khlopotov <[email protected]>
|
||||
imre Fitos <[email protected]>
|
||||
inglesp <[email protected]>
|
||||
Ingo Gottwald <[email protected]>
|
||||
Innovimax <[email protected]>
|
||||
Isaac Dupree <[email protected]>
|
||||
Isabel Jimenez <[email protected]>
|
||||
Isao Jonas <[email protected]>
|
||||
Iskander Sharipov <[email protected]>
|
||||
Ivan Babrou <[email protected]>
|
||||
Ivan Fraixedes <[email protected]>
|
||||
Ivan Grcic <[email protected]>
|
||||
@@ -785,6 +822,7 @@ James Mills <[email protected]>
|
||||
James Nesbitt <[email protected]>
|
||||
James Nugent <[email protected]>
|
||||
James Turnbull <[email protected]>
|
||||
James Watkins-Harvey <[email protected]>
|
||||
Jamie Hannaford <[email protected]>
|
||||
Jamshid Afshar <[email protected]>
|
||||
Jan Keromnes <[email protected]>
|
||||
@@ -817,6 +855,7 @@ jaxgeller <[email protected]>
|
||||
Jay <[email protected]>
|
||||
Jay <[email protected]>
|
||||
Jay Kamat <[email protected]>
|
||||
Jean Rouge <[email protected]>
|
||||
Jean-Baptiste Barth <[email protected]>
|
||||
Jean-Baptiste Dalido <[email protected]>
|
||||
Jean-Christophe Berthon <[email protected]>
|
||||
@@ -847,11 +886,13 @@ Jeroen Franse <[email protected]>
|
||||
Jeroen Jacobs <[email protected]>
|
||||
Jesse Dearing <[email protected]>
|
||||
Jesse Dubay <[email protected]>
|
||||
Jessica Frazelle <jessfraz@google.com>
|
||||
Jessica Frazelle <acidburn@microsoft.com>
|
||||
Jezeniel Zapanta <[email protected]>
|
||||
Jhon Honce <[email protected]>
|
||||
Ji.Zhilong <[email protected]>
|
||||
Jian Liao <[email protected]>
|
||||
Jian Zhang <[email protected]>
|
||||
Jiang Jinyang <[email protected]>
|
||||
Jie Luo <[email protected]>
|
||||
Jihyun Hwang <[email protected]>
|
||||
Jilles Oldenbeuving <[email protected]>
|
||||
@@ -862,14 +903,14 @@ Jim Perrin <[email protected]>
|
||||
Jimmy Cuadra <[email protected]>
|
||||
Jimmy Puckett <[email protected]>
|
||||
Jimmy Song <[email protected]>
|
||||
jimmyxian <[email protected]>
|
||||
Jinsoo Park <[email protected]>
|
||||
Jintao Zhang <[email protected]>
|
||||
Jiri Appl <[email protected]>
|
||||
Jiri Popelka <[email protected]>
|
||||
Jiuyue Ma <[email protected]>
|
||||
Jiří Župka <[email protected]>
|
||||
jjy <[email protected]>
|
||||
jmzwcn <[email protected]>
|
||||
Joao Fernandes <[email protected]>
|
||||
Joao Trindade <[email protected]>
|
||||
Joe Beda <[email protected]>
|
||||
Joe Doliner <[email protected]>
|
||||
Joe Ferguson <[email protected]>
|
||||
@@ -908,6 +949,7 @@ Jon Johnson <[email protected]>
|
||||
Jon Surrell <[email protected]>
|
||||
Jon Wedaman <[email protected]>
|
||||
Jonas Pfenniger <[email protected]>
|
||||
Jonathan A. Schweder <[email protected]>
|
||||
Jonathan A. Sternberg <[email protected]>
|
||||
Jonathan Boulle <[email protected]>
|
||||
Jonathan Camp <[email protected]>
|
||||
@@ -928,7 +970,7 @@ Jordan Jennings <[email protected]>
|
||||
Jordan Sissel <[email protected]>
|
||||
Jorge Marin <[email protected]>
|
||||
Jorit Kleine-Möllhoff <[email protected]>
|
||||
Jose Diaz-Gonzalez <jose@seatgeek.com>
|
||||
Jose Diaz-Gonzalez <email@josediazgonzalez.com>
|
||||
Joseph Anthony Pasquale Holsten <[email protected]>
|
||||
Joseph Hager <[email protected]>
|
||||
Joseph Kern <[email protected]>
|
||||
@@ -982,7 +1024,8 @@ kargakis <[email protected]>
|
||||
Karl Grzeszczak <[email protected]>
|
||||
Karol Duleba <[email protected]>
|
||||
Karthik Karanth <[email protected]>
|
||||
Karthik Nayak <K[email protected]>
|
||||
Karthik Nayak <k[email protected]>
|
||||
Kasper Fabæch Brandt <[email protected]>
|
||||
Kate Heddleston <[email protected]>
|
||||
Katie McLaughlin <[email protected]>
|
||||
Kato Kazuyoshi <[email protected]>
|
||||
@@ -990,6 +1033,7 @@ Katrina Owen <[email protected]>
|
||||
Kawsar Saiyeed <[email protected]>
|
||||
Kay Yan <[email protected]>
|
||||
kayrus <[email protected]>
|
||||
Kazuhiro Sera <[email protected]>
|
||||
Ke Li <[email protected]>
|
||||
Ke Xu <[email protected]>
|
||||
Kei Ohmura <[email protected]>
|
||||
@@ -998,6 +1042,7 @@ Keli Hu <[email protected]>
|
||||
Ken Cochrane <[email protected]>
|
||||
Ken Herner <[email protected]>
|
||||
Ken ICHIKAWA <[email protected]>
|
||||
Ken Reese <[email protected]>
|
||||
Kenfe-Mickaël Laventure <[email protected]>
|
||||
Kenjiro Nakayama <[email protected]>
|
||||
Kent Johnson <[email protected]>
|
||||
@@ -1035,11 +1080,13 @@ Krasimir Georgiev <[email protected]>
|
||||
Kris-Mikael Krister <[email protected]>
|
||||
Kristian Haugene <[email protected]>
|
||||
Kristina Zabunova <[email protected]>
|
||||
krrg <[email protected]>
|
||||
Krystian Wojcicki <[email protected]>
|
||||
Kun Zhang <[email protected]>
|
||||
Kunal Kushwaha <[email protected]>
|
||||
Kunal Tyagi <[email protected]>
|
||||
Kyle Conroy <[email protected]>
|
||||
Kyle Linden <[email protected]>
|
||||
Kyle Wuolle <[email protected]>
|
||||
kyu <[email protected]>
|
||||
Lachlan Coote <[email protected]>
|
||||
Lai Jiangshan <[email protected]>
|
||||
@@ -1060,6 +1107,7 @@ Leandro Siqueira <[email protected]>
|
||||
Lee Chao <[email protected]>
|
||||
Lee, Meng-Han <[email protected]>
|
||||
leeplay <[email protected]>
|
||||
Lei Gong <[email protected]>
|
||||
Lei Jitang <[email protected]>
|
||||
Len Weincier <[email protected]>
|
||||
Lennie <[email protected]>
|
||||
@@ -1076,6 +1124,8 @@ Liana Lo <[email protected]>
|
||||
Liang Mingqiang <[email protected]>
|
||||
Liang-Chi Hsieh <[email protected]>
|
||||
Liao Qingwei <[email protected]>
|
||||
Lifubang <[email protected]>
|
||||
Lihua Tang <[email protected]>
|
||||
Lily Guo <[email protected]>
|
||||
limsy <[email protected]>
|
||||
Lin Lu <[email protected]>
|
||||
@@ -1094,7 +1144,8 @@ Lloyd Dewolf <[email protected]>
|
||||
Lokesh Mandvekar <[email protected]>
|
||||
longliqiang88 <[email protected]>
|
||||
Lorenz Leutgeb <[email protected]>
|
||||
Lorenzo Fontana <lo@linux.com>
|
||||
Lorenzo Fontana <fontanalorenz@gmail.com>
|
||||
Lotus Fenn <[email protected]>
|
||||
Louis Opter <[email protected]>
|
||||
Luca Favatella <[email protected]>
|
||||
Luca Marturana <[email protected]>
|
||||
@@ -1151,6 +1202,7 @@ Marius Gundersen <[email protected]>
|
||||
Marius Sturm <[email protected]>
|
||||
Marius Voila <[email protected]>
|
||||
Mark Allen <[email protected]>
|
||||
Mark Jeromin <[email protected]>
|
||||
Mark McGranaghan <[email protected]>
|
||||
Mark McKinstry <[email protected]>
|
||||
Mark Milstein <[email protected]>
|
||||
@@ -1167,6 +1219,7 @@ Martijn van Oosterhout <[email protected]>
|
||||
Martin Honermeyer <[email protected]>
|
||||
Martin Kelly <[email protected]>
|
||||
Martin Mosegaard Amdisen <[email protected]>
|
||||
Martin Muzatko <[email protected]>
|
||||
Martin Redmond <[email protected]>
|
||||
Mary Anthony <[email protected]>
|
||||
Masahito Zembutsu <[email protected]>
|
||||
@@ -1200,6 +1253,7 @@ Matthias Klumpp <[email protected]>
|
||||
Matthias Kühnle <[email protected]>
|
||||
Matthias Rampke <[email protected]>
|
||||
Matthieu Hauglustaine <[email protected]>
|
||||
Mattias Jernberg <[email protected]>
|
||||
Mauricio Garavaglia <[email protected]>
|
||||
mauriyouth <[email protected]>
|
||||
Max Shytikov <[email protected]>
|
||||
@@ -1208,6 +1262,8 @@ Maxim Ivanov <[email protected]>
|
||||
Maxim Kulkin <[email protected]>
|
||||
Maxim Treskin <[email protected]>
|
||||
Maxime Petazzoni <[email protected]>
|
||||
Maximiliano Maccanti <[email protected]>
|
||||
Maxwell <[email protected]>
|
||||
Meaglith Ma <[email protected]>
|
||||
meejah <[email protected]>
|
||||
Megan Kostick <[email protected]>
|
||||
@@ -1248,8 +1304,9 @@ Michal Wieczorek <[email protected]>
|
||||
Michaël Pailloncy <[email protected]>
|
||||
Michał Czeraszkiewicz <[email protected]>
|
||||
Michał Gryko <[email protected]>
|
||||
Michiel@unhosted <[email protected]>
|
||||
Mickaël FORTUNATO <[email protected]>
|
||||
Michiel de Jong <[email protected]>
|
||||
Mickaël Fortunato <[email protected]>
|
||||
Mickaël Remars <[email protected]>
|
||||
Miguel Angel Fernández <[email protected]>
|
||||
Miguel Morales <[email protected]>
|
||||
Mihai Borobocea <[email protected]>
|
||||
@@ -1280,6 +1337,7 @@ Mitch Capper <[email protected]>
|
||||
Mizuki Urushida <[email protected]>
|
||||
mlarcher <[email protected]>
|
||||
Mohammad Banikazemi <[email protected]>
|
||||
Mohammad Nasirifar <[email protected]>
|
||||
Mohammed Aaqib Ansari <[email protected]>
|
||||
Mohit Soni <[email protected]>
|
||||
Moorthy RS <[email protected]>
|
||||
@@ -1304,6 +1362,7 @@ Nan Monnand Deng <[email protected]>
|
||||
Naoki Orii <[email protected]>
|
||||
Natalie Parker <[email protected]>
|
||||
Natanael Copa <[email protected]>
|
||||
Natasha Jarus <[email protected]>
|
||||
Nate Brennand <[email protected]>
|
||||
Nate Eagleson <[email protected]>
|
||||
Nate Jones <[email protected]>
|
||||
@@ -1337,6 +1396,7 @@ Nicolas Dudebout <[email protected]>
|
||||
Nicolas Goy <[email protected]>
|
||||
Nicolas Kaiser <[email protected]>
|
||||
Nicolas Sterchele <[email protected]>
|
||||
Nicolas V Castet <[email protected]>
|
||||
Nicolás Hock Isaza <[email protected]>
|
||||
Nigel Poulton <[email protected]>
|
||||
Nik Nyby <[email protected]>
|
||||
@@ -1352,6 +1412,7 @@ Noah Treuhaft <[email protected]>
|
||||
NobodyOnSE <[email protected]>
|
||||
noducks <[email protected]>
|
||||
Nolan Darilek <[email protected]>
|
||||
Noriki Nakamura <[email protected]>
|
||||
nponeccop <[email protected]>
|
||||
Nuutti Kotivuori <[email protected]>
|
||||
nzwsch <[email protected]>
|
||||
@@ -1363,8 +1424,11 @@ Ohad Schneider <[email protected]>
|
||||
ohmystack <[email protected]>
|
||||
Ole Reifschneider <[email protected]>
|
||||
Oliver Neal <[email protected]>
|
||||
Oliver Reason <[email protected]>
|
||||
Olivier Gambier <[email protected]>
|
||||
Olle Jonsson <[email protected]>
|
||||
Olli Janatuinen <[email protected]>
|
||||
Omri Shiv <[email protected]>
|
||||
Oriol Francès <[email protected]>
|
||||
Oskar Niburski <[email protected]>
|
||||
Otto Kekäläinen <[email protected]>
|
||||
@@ -1420,6 +1484,7 @@ Peter Edge <[email protected]>
|
||||
Peter Ericson <[email protected]>
|
||||
Peter Esbensen <[email protected]>
|
||||
Peter Jaffe <[email protected]>
|
||||
Peter Kang <[email protected]>
|
||||
Peter Malmgren <[email protected]>
|
||||
Peter Salvatore <[email protected]>
|
||||
Peter Volpe <[email protected]>
|
||||
@@ -1452,6 +1517,7 @@ Prasanna Gautam <[email protected]>
|
||||
Pratik Karki <[email protected]>
|
||||
Prayag Verma <[email protected]>
|
||||
Priya Wadhwa <[email protected]>
|
||||
Projjol Banerji <[email protected]>
|
||||
Przemek Hejman <[email protected]>
|
||||
Pure White <[email protected]>
|
||||
pysqz <[email protected]>
|
||||
@@ -1462,6 +1528,7 @@ Quentin Brossard <[email protected]>
|
||||
Quentin Perez <[email protected]>
|
||||
Quentin Tayssier <[email protected]>
|
||||
r0n22 <[email protected]>
|
||||
Radostin Stoyanov <[email protected]>
|
||||
Rafal Jeczalik <[email protected]>
|
||||
Rafe Colton <[email protected]>
|
||||
Raghavendra K T <[email protected]>
|
||||
@@ -1475,6 +1542,7 @@ Ralph Bean <[email protected]>
|
||||
Ramkumar Ramachandra <[email protected]>
|
||||
Ramon Brooker <[email protected]>
|
||||
Ramon van Alteren <[email protected]>
|
||||
RaviTeja Pothana <[email protected]>
|
||||
Ray Tsang <[email protected]>
|
||||
ReadmeCritic <[email protected]>
|
||||
Recursive Madman <[email protected]>
|
||||
@@ -1524,6 +1592,7 @@ Roel Van Nyen <[email protected]>
|
||||
Roger Peppe <[email protected]>
|
||||
Rohit Jnagal <[email protected]>
|
||||
Rohit Kadam <[email protected]>
|
||||
Rohit Kapur <[email protected]>
|
||||
Rojin George <[email protected]>
|
||||
Roland Huß <[email protected]>
|
||||
Roland Kammerer <[email protected]>
|
||||
@@ -1533,6 +1602,9 @@ Roman Dudin <[email protected]>
|
||||
Roman Strashkin <[email protected]>
|
||||
Ron Smits <[email protected]>
|
||||
Ron Williams <[email protected]>
|
||||
Rong Gao <[email protected]>
|
||||
Rong Zhang <[email protected]>
|
||||
Rongxiang Song <[email protected]>
|
||||
root <[email protected]>
|
||||
root <[email protected]>
|
||||
root <[email protected]>
|
||||
@@ -1544,8 +1616,10 @@ Rovanion Luckey <[email protected]>
|
||||
Royce Remer <[email protected]>
|
||||
Rozhnov Alexandr <[email protected]>
|
||||
Rudolph Gottesheim <[email protected]>
|
||||
Rui Cao <[email protected]>
|
||||
Rui Lopes <[email protected]>
|
||||
Runshen Zhu <[email protected]>
|
||||
Russ Magee <[email protected]>
|
||||
Ryan Abrams <[email protected]>
|
||||
Ryan Anderson <[email protected]>
|
||||
Ryan Aslett <[email protected]>
|
||||
@@ -1564,6 +1638,7 @@ Ryan Wallner <[email protected]>
|
||||
Ryan Zhang <[email protected]>
|
||||
ryancooper7 <[email protected]>
|
||||
RyanDeng <[email protected]>
|
||||
Ryo Nakao <[email protected]>
|
||||
Rémy Greinhofer <[email protected]>
|
||||
s. rannou <[email protected]>
|
||||
s00318865 <[email protected]>
|
||||
@@ -1572,6 +1647,7 @@ Sachin Joshi <[email protected]>
|
||||
Sagar Hani <[email protected]>
|
||||
Sainath Grandhi <[email protected]>
|
||||
Sakeven Jiang <[email protected]>
|
||||
Salahuddin Khan <[email protected]>
|
||||
Sally O'Malley <[email protected]>
|
||||
Sam Abed <[email protected]>
|
||||
Sam Alba <[email protected]>
|
||||
@@ -1593,6 +1669,7 @@ Santhosh Manohar <[email protected]>
|
||||
sapphiredev <[email protected]>
|
||||
Sargun Dhillon <[email protected]>
|
||||
Sascha Andres <[email protected]>
|
||||
Sascha Grunert <[email protected]>
|
||||
Satnam Singh <[email protected]>
|
||||
Satoshi Amemiya <[email protected]>
|
||||
Satoshi Tagomori <[email protected]>
|
||||
@@ -1619,7 +1696,9 @@ Serge Hallyn <[email protected]>
|
||||
Sergey Alekseev <[email protected]>
|
||||
Sergey Evstifeev <[email protected]>
|
||||
Sergii Kabashniuk <[email protected]>
|
||||
Sergio Lopez <[email protected]>
|
||||
Serhat Gülçiçek <[email protected]>
|
||||
SeungUkLee <[email protected]>
|
||||
Sevki Hasirci <[email protected]>
|
||||
Shane Canon <[email protected]>
|
||||
Shane da Silva <[email protected]>
|
||||
@@ -1647,6 +1726,7 @@ Sidhartha Mani <[email protected]>
|
||||
sidharthamani <[email protected]>
|
||||
Silas Sewell <[email protected]>
|
||||
Silvan Jegen <[email protected]>
|
||||
Simão Reis <[email protected]>
|
||||
Simei He <[email protected]>
|
||||
Simon Eskildsen <[email protected]>
|
||||
Simon Ferquel <[email protected]>
|
||||
@@ -1714,10 +1794,11 @@ tang0th <[email protected]>
|
||||
Tangi Colin <[email protected]>
|
||||
Tatsuki Sugiura <[email protected]>
|
||||
Tatsushi Inagaki <[email protected]>
|
||||
Taylan Isikdemir <[email protected]>
|
||||
Taylor Jones <[email protected]>
|
||||
tbonza <[email protected]>
|
||||
Ted M. Young <[email protected]>
|
||||
Tehmasp Chaudhri <[email protected]>
|
||||
Tejaswini Duggaraju <[email protected]>
|
||||
Tejesh Mehta <[email protected]>
|
||||
terryding77 <[email protected]>
|
||||
tgic <[email protected]>
|
||||
@@ -1811,6 +1892,7 @@ Tristan Carel <[email protected]>
|
||||
Troy Denton <[email protected]>
|
||||
Tycho Andersen <[email protected]>
|
||||
Tyler Brock <[email protected]>
|
||||
Tyler Brown <[email protected]>
|
||||
Tzu-Jung Lee <[email protected]>
|
||||
uhayate <[email protected]>
|
||||
Ulysse Carion <[email protected]>
|
||||
@@ -1871,6 +1953,7 @@ Wassim Dhif <[email protected]>
|
||||
Wayne Chang <[email protected]>
|
||||
Wayne Song <[email protected]>
|
||||
Weerasak Chongnguluam <[email protected]>
|
||||
Wei Fu <[email protected]>
|
||||
Wei Wu <[email protected]>
|
||||
Wei-Ting Kuo <[email protected]>
|
||||
weipeng <[email protected]>
|
||||
@@ -1900,17 +1983,24 @@ WiseTrem <[email protected]>
|
||||
Wolfgang Powisch <[email protected]>
|
||||
Wonjun Kim <[email protected]>
|
||||
xamyzhao <[email protected]>
|
||||
Xian Chaobo <[email protected]>
|
||||
Xianglin Gao <[email protected]>
|
||||
Xianlu Bird <[email protected]>
|
||||
Xiao YongBiao <[email protected]>
|
||||
XiaoBing Jiang <[email protected]>
|
||||
Xiaodong Zhang <[email protected]>
|
||||
Xiaoxi He <[email protected]>
|
||||
Xiaoxu Chen <[email protected]>
|
||||
Xiaoyu Zhang <[email protected]>
|
||||
xichengliudui <[email protected]>
|
||||
xiekeyang <[email protected]>
|
||||
Ximo Guanter Gonzálbez <[email protected]>
|
||||
Xinbo Weng <[email protected]>
|
||||
Xinzi Zhou <[email protected]>
|
||||
Xiuming Chen <[email protected]>
|
||||
Xuecong Liao <[email protected]>
|
||||
xuzhaokui <[email protected]>
|
||||
Yadnyawalkya Tale <[email protected]>
|
||||
Yahya <[email protected]>
|
||||
YAMADA Tsuyoshi <[email protected]>
|
||||
Yamasaki Masahide <[email protected]>
|
||||
@@ -1930,6 +2020,7 @@ Yihang Ho <[email protected]>
|
||||
Ying Li <[email protected]>
|
||||
Yohei Ueda <[email protected]>
|
||||
Yong Tang <[email protected]>
|
||||
Yongxin Li <[email protected]>
|
||||
Yongzhi Pan <[email protected]>
|
||||
Yosef Fertel <[email protected]>
|
||||
You-Sheng Yang (楊有勝) <[email protected]>
|
||||
@@ -1940,9 +2031,12 @@ Yu Peng <[email protected]>
|
||||
Yu-Ju Hong <[email protected]>
|
||||
Yuan Sun <[email protected]>
|
||||
Yuanhong Peng <[email protected]>
|
||||
Yue Zhang <[email protected]>
|
||||
Yuhao Fang <[email protected]>
|
||||
Yuichiro Kaneko <[email protected]>
|
||||
Yunxiang Huang <[email protected]>
|
||||
Yurii Rashkovskii <[email protected]>
|
||||
Yusuf Tarık Günaydın <[email protected]>
|
||||
Yves Junqueira <[email protected]>
|
||||
Zac Dover <[email protected]>
|
||||
Zach Borboa <[email protected]>
|
||||
@@ -1959,8 +2053,10 @@ ZhangHang <[email protected]>
|
||||
zhangxianwei <[email protected]>
|
||||
Zhenan Ye <[email protected]>
|
||||
zhenghenghuo <[email protected]>
|
||||
Zhenhai Gao <[email protected]>
|
||||
Zhenkun Bi <[email protected]>
|
||||
Zhou Hao <[email protected]>
|
||||
Zhoulin Xie <[email protected]>
|
||||
Zhu Guihua <[email protected]>
|
||||
Zhu Kunjia <[email protected]>
|
||||
Zhuoyun Wei <[email protected]>
|
||||
|
||||
+1
-1
@@ -176,7 +176,7 @@
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2013-2017 Docker, Inc.
|
||||
Copyright 2013-2018 Docker, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ Copyright 2012-2017 Docker, Inc.
|
||||
|
||||
This product includes software developed at Docker, Inc. (https://www.docker.com).
|
||||
|
||||
This product contains software (https://github.com/kr/pty) developed
|
||||
This product contains software (https://github.com/creack/pty) developed
|
||||
by Keith Rarick, licensed under the MIT License.
|
||||
|
||||
The following is courtesy of our legal counsel:
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package api // import "github.com/docker/docker/api"
|
||||
// Common constants for daemon and client.
|
||||
const (
|
||||
// DefaultVersion of Current REST API
|
||||
DefaultVersion = "1.39"
|
||||
DefaultVersion = "1.40"
|
||||
|
||||
// NoBaseImageSpecifier is the symbol used by the FROM
|
||||
// command to specify that no base image is to be used.
|
||||
|
||||
+503
-169
File diff suppressed because it is too large.
Load diff
+10
-1
@@ -50,7 +50,7 @@ type ContainerCommitOptions struct {
|
||||
|
||||
// ContainerExecInspect holds information returned by exec inspect.
|
||||
type ContainerExecInspect struct {
|
||||
ExecID string
|
||||
ExecID string `json:"ID"`
|
||||
ContainerID string
|
||||
Running bool
|
||||
ExitCode int
|
||||
@@ -187,6 +187,15 @@ type ImageBuildOptions struct {
|
||||
// build request. The same identifier can be used to gracefully cancel the
|
||||
// build with the cancel request.
|
||||
BuildID string
|
||||
// Outputs defines configurations for exporting build results. Only supported
|
||||
// in BuildKit mode
|
||||
Outputs []ImageBuildOutput
|
||||
}
|
||||
|
||||
// ImageBuildOutput defines configuration for exporting a build result
|
||||
type ImageBuildOutput struct {
|
||||
Type string
|
||||
Attrs map[string]string
|
||||
}
|
||||
|
||||
// BuilderVersion sets the version of underlying builder to use
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ type Config struct {
|
||||
Env []string // List of environment variable to set in the container
|
||||
Cmd strslice.StrSlice // Command to run when starting the container
|
||||
Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
|
||||
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (Windows specific)
|
||||
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (meaning treat as a command line) (Windows specific).
|
||||
Image string // Name of the image as it was passed by the operator (e.g. could be symbolic)
|
||||
Volumes map[string]struct{} // List of volumes (mounts) used for the container
|
||||
WorkingDir string // Current directory (PWD) in the command will be launched
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package container
|
||||
package container // import "github.com/docker/docker/api/types/container"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DO NOT EDIT THIS FILE
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package container
|
||||
package container // import "github.com/docker/docker/api/types/container"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DO NOT EDIT THIS FILE
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package container
|
||||
package container // import "github.com/docker/docker/api/types/container"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DO NOT EDIT THIS FILE
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package container
|
||||
package container // import "github.com/docker/docker/api/types/container"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DO NOT EDIT THIS FILE
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package container
|
||||
package container // import "github.com/docker/docker/api/types/container"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DO NOT EDIT THIS FILE
|
||||
|
||||
+17
-5
@@ -244,6 +244,16 @@ func (n PidMode) Container() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// DeviceRequest represents a request for devices from a device driver.
|
||||
// Used by GPU device drivers.
|
||||
type DeviceRequest struct {
|
||||
Driver string // Name of device driver
|
||||
Count int // Number of devices to request (-1 = All)
|
||||
DeviceIDs []string // List of device IDs as recognizable by the device driver
|
||||
Capabilities [][]string // An OR list of AND lists of device capabilities (e.g. "gpu")
|
||||
Options map[string]string // Options to pass onto the device driver
|
||||
}
|
||||
|
||||
// DeviceMapping represents the device mapping between the host and the container.
|
||||
type DeviceMapping struct {
|
||||
PathOnHost string
|
||||
@@ -327,13 +337,14 @@ type Resources struct {
|
||||
CpusetMems string // CpusetMems 0-2, 0,1
|
||||
Devices []DeviceMapping // List of devices to map inside the container
|
||||
DeviceCgroupRules []string // List of rule to be added to the device cgroup
|
||||
DiskQuota int64 // Disk limit (in bytes)
|
||||
DeviceRequests []DeviceRequest // List of device requests for device drivers
|
||||
KernelMemory int64 // Kernel memory limit (in bytes)
|
||||
KernelMemoryTCP int64 // Hard limit for kernel TCP buffer memory (in bytes)
|
||||
MemoryReservation int64 // Memory soft limit (in bytes)
|
||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap
|
||||
MemorySwappiness *int64 // Tuning container memory swappiness behaviour
|
||||
OomKillDisable *bool // Whether to disable OOM Killer or not
|
||||
PidsLimit int64 // Setting pids limit for a container
|
||||
PidsLimit *int64 // Setting PIDs limit for a container; Set `0` or `-1` for unlimited, or `null` to not change.
|
||||
Ulimits []*units.Ulimit // List of ulimits to be set in the container
|
||||
|
||||
// Applicable to Windows
|
||||
@@ -369,9 +380,10 @@ type HostConfig struct {
|
||||
// Applicable to UNIX platforms
|
||||
CapAdd strslice.StrSlice // List of kernel capabilities to add to the container
|
||||
CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container
|
||||
DNS []string `json:"Dns"` // List of DNS server to lookup
|
||||
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for
|
||||
DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for
|
||||
Capabilities []string `json:"Capabilities"` // List of kernel capabilities to be available for container (this overrides the default set)
|
||||
DNS []string `json:"Dns"` // List of DNS server to lookup
|
||||
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for
|
||||
DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for
|
||||
ExtraHosts []string // List of extra hosts
|
||||
GroupAdd []string // List of additional groups that the container process will run as
|
||||
IpcMode IpcMode // IPC namespace to use for the container
|
||||
|
||||
+22
-48
@@ -5,7 +5,6 @@ package filters // import "github.com/docker/docker/api/types/filters"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@@ -37,39 +36,13 @@ func NewArgs(initialArgs ...KeyValuePair) Args {
|
||||
return args
|
||||
}
|
||||
|
||||
// ParseFlag parses a key=value string and adds it to an Args.
|
||||
//
|
||||
// Deprecated: Use Args.Add()
|
||||
func ParseFlag(arg string, prev Args) (Args, error) {
|
||||
filters := prev
|
||||
if len(arg) == 0 {
|
||||
return filters, nil
|
||||
// Keys returns all the keys in list of Args
|
||||
func (args Args) Keys() []string {
|
||||
keys := make([]string, 0, len(args.fields))
|
||||
for k := range args.fields {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
if !strings.Contains(arg, "=") {
|
||||
return filters, ErrBadFormat
|
||||
}
|
||||
|
||||
f := strings.SplitN(arg, "=", 2)
|
||||
|
||||
name := strings.ToLower(strings.TrimSpace(f[0]))
|
||||
value := strings.TrimSpace(f[1])
|
||||
|
||||
filters.Add(name, value)
|
||||
|
||||
return filters, nil
|
||||
}
|
||||
|
||||
// ErrBadFormat is an error returned when a filter is not in the form key=value
|
||||
//
|
||||
// Deprecated: this error will be removed in a future version
|
||||
var ErrBadFormat = errors.New("bad format of filter (expected name=value)")
|
||||
|
||||
// ToParam encodes the Args as args JSON encoded string
|
||||
//
|
||||
// Deprecated: use ToJSON
|
||||
func ToParam(a Args) (string, error) {
|
||||
return ToJSON(a)
|
||||
return keys
|
||||
}
|
||||
|
||||
// MarshalJSON returns a JSON byte representation of the Args
|
||||
@@ -107,13 +80,6 @@ func ToParamWithVersion(version string, a Args) (string, error) {
|
||||
return ToJSON(a)
|
||||
}
|
||||
|
||||
// FromParam decodes a JSON encoded string into Args
|
||||
//
|
||||
// Deprecated: use FromJSON
|
||||
func FromParam(p string) (Args, error) {
|
||||
return FromJSON(p)
|
||||
}
|
||||
|
||||
// FromJSON decodes a JSON encoded string into Args
|
||||
func FromJSON(p string) (Args, error) {
|
||||
args := NewArgs()
|
||||
@@ -275,14 +241,6 @@ func (args Args) FuzzyMatch(key, source string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Include returns true if the key exists in the mapping
|
||||
//
|
||||
// Deprecated: use Contains
|
||||
func (args Args) Include(field string) bool {
|
||||
_, ok := args.fields[field]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Contains returns true if the key exists in the mapping
|
||||
func (args Args) Contains(field string) bool {
|
||||
_, ok := args.fields[field]
|
||||
@@ -323,6 +281,22 @@ func (args Args) WalkValues(field string, op func(value string) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Clone returns a copy of args.
|
||||
func (args Args) Clone() (newArgs Args) {
|
||||
newArgs.fields = make(map[string]map[string]bool, len(args.fields))
|
||||
for k, m := range args.fields {
|
||||
var mm map[string]bool
|
||||
if m != nil {
|
||||
mm = make(map[string]bool, len(m))
|
||||
for kk, v := range m {
|
||||
mm[kk] = v
|
||||
}
|
||||
}
|
||||
newArgs.fields[k] = mm
|
||||
}
|
||||
return newArgs
|
||||
}
|
||||
|
||||
func deprecatedArgs(d map[string][]string) map[string]map[string]bool {
|
||||
m := map[string]map[string]bool{}
|
||||
for k, v := range d {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package image
|
||||
package image // import "github.com/docker/docker/api/types/image"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DO NOT EDIT THIS FILE
|
||||
|
||||
+2
-1
@@ -79,7 +79,8 @@ const (
|
||||
|
||||
// BindOptions defines options specific to mounts of type "bind".
|
||||
type BindOptions struct {
|
||||
Propagation Propagation `json:",omitempty"`
|
||||
Propagation Propagation `json:",omitempty"`
|
||||
NonRecursive bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
// VolumeOptions represents the options for a mount of type volume.
|
||||
|
||||
+7
-6
@@ -112,12 +112,13 @@ type ConfigReference struct {
|
||||
}
|
||||
|
||||
var acceptedFilters = map[string]bool{
|
||||
"driver": true,
|
||||
"type": true,
|
||||
"name": true,
|
||||
"id": true,
|
||||
"label": true,
|
||||
"scope": true,
|
||||
"dangling": true,
|
||||
"driver": true,
|
||||
"id": true,
|
||||
"label": true,
|
||||
"name": true,
|
||||
"scope": true,
|
||||
"type": true,
|
||||
}
|
||||
|
||||
// ValidateFilters validates the list of filter args with the available filters.
|
||||
|
||||
+3
-2
@@ -77,8 +77,9 @@ type Arg struct {
|
||||
|
||||
// Filter is used to conditionally apply Seccomp rules
|
||||
type Filter struct {
|
||||
Caps []string `json:"caps,omitempty"`
|
||||
Arches []string `json:"arches,omitempty"`
|
||||
Caps []string `json:"caps,omitempty"`
|
||||
Arches []string `json:"arches,omitempty"`
|
||||
MinKernel string `json:"minKernel,omitempty"`
|
||||
}
|
||||
|
||||
// Syscall is used to match a group of syscalls in Seccomp
|
||||
|
||||
+2
-2
@@ -120,7 +120,7 @@ type NetworkStats struct {
|
||||
RxBytes uint64 `json:"rx_bytes"`
|
||||
// Packets received. Windows and Linux.
|
||||
RxPackets uint64 `json:"rx_packets"`
|
||||
// Received errors. Not used on Windows. Note that we dont `omitempty` this
|
||||
// Received errors. Not used on Windows. Note that we don't `omitempty` this
|
||||
// field as it is expected in the >=v1.21 API stats structure.
|
||||
RxErrors uint64 `json:"rx_errors"`
|
||||
// Incoming packets dropped. Windows and Linux.
|
||||
@@ -129,7 +129,7 @@ type NetworkStats struct {
|
||||
TxBytes uint64 `json:"tx_bytes"`
|
||||
// Packets sent. Windows and Linux.
|
||||
TxPackets uint64 `json:"tx_packets"`
|
||||
// Sent errors. Not used on Windows. Note that we dont `omitempty` this
|
||||
// Sent errors. Not used on Windows. Note that we don't `omitempty` this
|
||||
// field as it is expected in the >=v1.21 API stats structure.
|
||||
TxErrors uint64 `json:"tx_errors"`
|
||||
// Outgoing packets dropped. Windows and Linux.
|
||||
|
||||
+6
-1
@@ -27,9 +27,14 @@ type ConfigReferenceFileTarget struct {
|
||||
Mode os.FileMode
|
||||
}
|
||||
|
||||
// ConfigReferenceRuntimeTarget is a target for a config specifying that it
|
||||
// isn't mounted into the container but instead has some other purpose.
|
||||
type ConfigReferenceRuntimeTarget struct{}
|
||||
|
||||
// ConfigReference is a reference to a config in swarm
|
||||
type ConfigReference struct {
|
||||
File *ConfigReferenceFileTarget
|
||||
File *ConfigReferenceFileTarget `json:",omitempty"`
|
||||
Runtime *ConfigReferenceRuntimeTarget `json:",omitempty"`
|
||||
ConfigID string
|
||||
ConfigName string
|
||||
}
|
||||
+2
@@ -33,6 +33,7 @@ type SELinuxContext struct {
|
||||
|
||||
// CredentialSpec for managed service account (Windows only)
|
||||
type CredentialSpec struct {
|
||||
Config string
|
||||
File string
|
||||
Registry string
|
||||
}
|
||||
@@ -71,4 +72,5 @@ type ContainerSpec struct {
|
||||
Secrets []*SecretReference `json:",omitempty"`
|
||||
Configs []*ConfigReference `json:",omitempty"`
|
||||
Isolation container.Isolation `json:",omitempty"`
|
||||
Sysctls map[string]string `json:",omitempty"`
|
||||
}
|
||||
+4
@@ -14,6 +14,7 @@ type ClusterInfo struct {
|
||||
RootRotationInProgress bool
|
||||
DefaultAddrPool []string
|
||||
SubnetSize uint32
|
||||
DataPathPort uint32
|
||||
}
|
||||
|
||||
// Swarm represents a swarm.
|
||||
@@ -153,6 +154,7 @@ type InitRequest struct {
|
||||
ListenAddr string
|
||||
AdvertiseAddr string
|
||||
DataPathAddr string
|
||||
DataPathPort uint32
|
||||
ForceNewCluster bool
|
||||
Spec Spec
|
||||
AutoLockManagers bool
|
||||
@@ -207,6 +209,8 @@ type Info struct {
|
||||
Managers int `json:",omitempty"`
|
||||
|
||||
Cluster *ClusterInfo `json:",omitempty"`
|
||||
|
||||
Warnings []string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Peer represents a peer.
|
||||
|
||||
+1
@@ -127,6 +127,7 @@ type ResourceRequirements struct {
|
||||
type Placement struct {
|
||||
Constraints []string `json:",omitempty"`
|
||||
Preferences []PlacementPreference `json:",omitempty"`
|
||||
MaxReplicas uint64 `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,
|
||||
|
||||
+2
@@ -158,10 +158,12 @@ type Info struct {
|
||||
MemoryLimit bool
|
||||
SwapLimit bool
|
||||
KernelMemory bool
|
||||
KernelMemoryTCP bool
|
||||
CPUCfsPeriod bool `json:"CpuCfsPeriod"`
|
||||
CPUCfsQuota bool `json:"CpuCfsQuota"`
|
||||
CPUShares bool
|
||||
CPUSet bool
|
||||
PidsLimit bool
|
||||
IPv4Forwarding bool
|
||||
BridgeNfIptables bool
|
||||
BridgeNfIP6tables bool `json:"BridgeNfIp6tables"`
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package volume
|
||||
package volume // import "github.com/docker/docker/api/types/volume"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DO NOT EDIT THIS FILE
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package volume
|
||||
package volume // import "github.com/docker/docker/api/types/volume"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DO NOT EDIT THIS FILE
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
cli, err := client.NewEnvClient()
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
+2
-6
@@ -11,10 +11,6 @@ func (cli *Client) BuildCancel(ctx context.Context, id string) error {
|
||||
query.Set("id", id)
|
||||
|
||||
serverResp, err := cli.post(ctx, "/build/cancel", query, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
return nil
|
||||
ensureReaderClosed(serverResp)
|
||||
return err
|
||||
}
|
||||
+1
-1
@@ -31,11 +31,11 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePru
|
||||
query.Set("filters", filters)
|
||||
|
||||
serverResp, err := cli.post(ctx, "/build/prune", query, nil, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
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)
|
||||
|
||||
+1
-1
@@ -18,11 +18,11 @@ func (cli *Client) CheckpointList(ctx context.Context, container string, options
|
||||
}
|
||||
|
||||
resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return checkpoints, wrapResponseError(err, resp, "container", container)
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.body).Decode(&checkpoints)
|
||||
ensureReaderClosed(resp)
|
||||
return checkpoints, err
|
||||
}
|
||||
+52
-165
@@ -23,7 +23,7 @@ For example, to list running containers (the equivalent of "docker ps"):
|
||||
)
|
||||
|
||||
func main() {
|
||||
cli, err := client.NewEnvClient()
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -47,16 +47,13 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"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/tlsconfig"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -84,13 +81,22 @@ type Client struct {
|
||||
customHTTPHeaders map[string]string
|
||||
// manualOverride is set to true when the version was set by users.
|
||||
manualOverride bool
|
||||
|
||||
// negotiateVersion indicates if the client should automatically negotiate
|
||||
// the API version to use when making requests. API version negotiation is
|
||||
// performed on the first request, after which negotiated is set to "true"
|
||||
// so that subsequent requests do not re-negotiate.
|
||||
negotiateVersion bool
|
||||
|
||||
// negotiated indicates that API version negotiation took place
|
||||
negotiated 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
|
||||
// The Docker client (and by extension docker API client) can be made 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.
|
||||
@@ -103,137 +109,6 @@ func CheckRedirect(req *http.Request, via []*http.Request) error {
|
||||
return ErrRedirect
|
||||
}
|
||||
|
||||
// NewEnvClient initializes a new API client based on environment variables.
|
||||
// See FromEnv for a list of support environment variables.
|
||||
//
|
||||
// Deprecated: use NewClientWithOpts(FromEnv)
|
||||
func NewEnvClient() (*Client, error) {
|
||||
return NewClientWithOpts(FromEnv)
|
||||
}
|
||||
|
||||
// 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 != "" {
|
||||
options := tlsconfig.Options{
|
||||
CAFile: filepath.Join(dockerCertPath, "ca.pem"),
|
||||
CertFile: filepath.Join(dockerCertPath, "cert.pem"),
|
||||
KeyFile: filepath.Join(dockerCertPath, "key.pem"),
|
||||
InsecureSkipVerify: os.Getenv("DOCKER_TLS_VERIFY") == "",
|
||||
}
|
||||
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.
|
||||
// Deprecated: use WithDialContext
|
||||
func WithDialer(dialer *net.Dialer) func(*Client) error {
|
||||
return WithDialContext(dialer.DialContext)
|
||||
}
|
||||
|
||||
// WithDialContext applies the dialer to the client transport. This can be
|
||||
// used to set the Timeout and KeepAlive settings of the client.
|
||||
func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if transport, ok := c.client.Transport.(*http.Transport); ok {
|
||||
transport.DialContext = 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.
|
||||
@@ -241,7 +116,7 @@ func WithHTTPHeaders(headers map[string]string) func(*Client) error {
|
||||
// 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) {
|
||||
func NewClientWithOpts(ops ...Opt) (*Client, error) {
|
||||
client, err := defaultHTTPClient(DefaultDockerHost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -249,7 +124,6 @@ func NewClientWithOpts(ops ...func(*Client) error) (*Client, error) {
|
||||
c := &Client{
|
||||
host: DefaultDockerHost,
|
||||
version: api.DefaultVersion,
|
||||
scheme: "http",
|
||||
client: client,
|
||||
proto: defaultProto,
|
||||
addr: defaultAddr,
|
||||
@@ -264,14 +138,18 @@ func NewClientWithOpts(ops ...func(*Client) error) (*Client, error) {
|
||||
if _, ok := c.client.Transport.(http.RoundTripper); !ok {
|
||||
return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", c.client.Transport)
|
||||
}
|
||||
tlsConfig := resolveTLSConfig(c.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.
|
||||
c.scheme = "https"
|
||||
if c.scheme == "" {
|
||||
c.scheme = "http"
|
||||
|
||||
tlsConfig := resolveTLSConfig(c.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.
|
||||
c.scheme = "https"
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
@@ -290,18 +168,6 @@ func defaultHTTPClient(host string) (*http.Client, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewClient initializes a new API client for the given host and API version.
|
||||
// It uses the given http client as transport.
|
||||
// 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.
|
||||
// Deprecated: use NewClientWithOpts
|
||||
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))
|
||||
}
|
||||
|
||||
// Close the transport used by the client
|
||||
func (cli *Client) Close() error {
|
||||
if t, ok := cli.client.Transport.(*http.Transport); ok {
|
||||
@@ -312,8 +178,11 @@ func (cli *Client) Close() error {
|
||||
|
||||
// getAPIPath returns the versioned request path to call the api.
|
||||
// It appends the query parameters to the path if they are not empty.
|
||||
func (cli *Client) getAPIPath(p string, query url.Values) string {
|
||||
func (cli *Client) getAPIPath(ctx context.Context, p string, query url.Values) string {
|
||||
var apiPath string
|
||||
if cli.negotiateVersion && !cli.negotiated {
|
||||
cli.NegotiateAPIVersion(ctx)
|
||||
}
|
||||
if cli.version != "" {
|
||||
v := strings.TrimPrefix(cli.version, "v")
|
||||
apiPath = path.Join(cli.basePath, "/v"+v, p)
|
||||
@@ -329,19 +198,31 @@ func (cli *Client) ClientVersion() string {
|
||||
}
|
||||
|
||||
// NegotiateAPIVersion queries the API and updates the version to match the
|
||||
// API version. Any errors are silently ignored.
|
||||
// API version. Any errors are silently ignored. If a manual override is in place,
|
||||
// either through the `DOCKER_API_VERSION` environment variable, or if the client
|
||||
// was initialized with a fixed version (`opts.WithVersion(xx)`), no negotiation
|
||||
// will be performed.
|
||||
func (cli *Client) NegotiateAPIVersion(ctx context.Context) {
|
||||
ping, _ := cli.Ping(ctx)
|
||||
cli.NegotiateAPIVersionPing(ping)
|
||||
if !cli.manualOverride {
|
||||
ping, _ := cli.Ping(ctx)
|
||||
cli.negotiateAPIVersionPing(ping)
|
||||
}
|
||||
}
|
||||
|
||||
// NegotiateAPIVersionPing updates the client version to match the Ping.APIVersion
|
||||
// if the ping version is less than the default version.
|
||||
// if the ping version is less than the default version. If a manual override is
|
||||
// in place, either through the `DOCKER_API_VERSION` environment variable, or if
|
||||
// the client was initialized with a fixed version (`opts.WithVersion(xx)`), no
|
||||
// negotiation is performed.
|
||||
func (cli *Client) NegotiateAPIVersionPing(p types.Ping) {
|
||||
if cli.manualOverride {
|
||||
return
|
||||
if !cli.manualOverride {
|
||||
cli.negotiateAPIVersionPing(p)
|
||||
}
|
||||
}
|
||||
|
||||
// negotiateAPIVersionPing queries the API and updates the version to match the
|
||||
// API version. Any errors are silently ignored.
|
||||
func (cli *Client) negotiateAPIVersionPing(p types.Ping) {
|
||||
// try the latest version before versioning headers existed
|
||||
if p.APIVersion == "" {
|
||||
p.APIVersion = "1.24"
|
||||
@@ -356,6 +237,12 @@ func (cli *Client) NegotiateAPIVersionPing(p types.Ping) {
|
||||
if versions.LessThan(p.APIVersion, cli.version) {
|
||||
cli.version = p.APIVersion
|
||||
}
|
||||
|
||||
// Store the results, so that automatic API version negotiation (if enabled)
|
||||
// won't be performed on the next request.
|
||||
if cli.negotiateVersion {
|
||||
cli.negotiated = true
|
||||
}
|
||||
}
|
||||
|
||||
// DaemonHost returns the host address used by the client
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package client
|
||||
|
||||
import "net/http"
|
||||
|
||||
// NewClient initializes a new API client for the given host and API version.
|
||||
// It uses the given http client as transport.
|
||||
// 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.
|
||||
// Deprecated: use NewClientWithOpts
|
||||
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))
|
||||
}
|
||||
|
||||
// NewEnvClient initializes a new API client based on environment variables.
|
||||
// See FromEnv for a list of support environment variables.
|
||||
//
|
||||
// Deprecated: use NewClientWithOpts(FromEnv)
|
||||
func NewEnvClient() (*Client, error) {
|
||||
return NewClientWithOpts(FromEnv)
|
||||
}
|
||||
+1
-1
@@ -15,11 +15,11 @@ func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (t
|
||||
return response, err
|
||||
}
|
||||
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.body).Decode(&response)
|
||||
ensureReaderClosed(resp)
|
||||
return response, err
|
||||
}
|
||||
+1
-1
@@ -18,10 +18,10 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C
|
||||
return swarm.Config{}, nil, err
|
||||
}
|
||||
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return swarm.Config{}, nil, wrapResponseError(err, resp, "config", id)
|
||||
}
|
||||
defer ensureReaderClosed(resp)
|
||||
|
||||
body, err := ioutil.ReadAll(resp.body)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -27,12 +27,12 @@ func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptio
|
||||
}
|
||||
|
||||
resp, err := cli.get(ctx, "/configs", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var configs []swarm.Config
|
||||
err = json.NewDecoder(resp.body).Decode(&configs)
|
||||
ensureReaderClosed(resp)
|
||||
return configs, err
|
||||
}
|
||||
+1
-1
@@ -8,6 +8,6 @@ func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
|
||||
return err
|
||||
}
|
||||
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
|
||||
ensureReaderClosed(resp)
|
||||
defer ensureReaderClosed(resp)
|
||||
return wrapResponseError(err, resp, "config", id)
|
||||
}
|
||||
+1
-1
@@ -45,11 +45,11 @@ func (cli *Client) ContainerCommit(ctx context.Context, container string, option
|
||||
|
||||
var response types.IDResponse
|
||||
resp, err := cli.post(ctx, "/commit", query, options.Config, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.body).Decode(&response)
|
||||
ensureReaderClosed(resp)
|
||||
return response, err
|
||||
}
|
||||
+4
-2
@@ -21,10 +21,10 @@ func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path stri
|
||||
|
||||
urlStr := "/containers/" + containerID + "/archive"
|
||||
response, err := cli.head(ctx, urlStr, query, nil)
|
||||
defer ensureReaderClosed(response)
|
||||
if err != nil {
|
||||
return types.ContainerPathStat{}, wrapResponseError(err, response, "container:path", containerID+":"+path)
|
||||
}
|
||||
defer ensureReaderClosed(response)
|
||||
return getContainerPathStatFromHeader(response.header)
|
||||
}
|
||||
|
||||
@@ -45,11 +45,12 @@ func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath str
|
||||
apiPath := "/containers/" + containerID + "/archive"
|
||||
|
||||
response, err := cli.putRaw(ctx, apiPath, query, content, nil)
|
||||
defer ensureReaderClosed(response)
|
||||
if err != nil {
|
||||
return wrapResponseError(err, response, "container:path", containerID+":"+dstPath)
|
||||
}
|
||||
defer ensureReaderClosed(response)
|
||||
|
||||
// TODO this code converts non-error status-codes (e.g., "204 No Content") into an error; verify if this is the desired behavior
|
||||
if response.statusCode != http.StatusOK {
|
||||
return fmt.Errorf("unexpected status code from daemon: %d", response.statusCode)
|
||||
}
|
||||
@@ -69,6 +70,7 @@ func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath s
|
||||
return nil, types.ContainerPathStat{}, wrapResponseError(err, response, "container:path", containerID+":"+srcPath)
|
||||
}
|
||||
|
||||
// TODO this code converts non-error status-codes (e.g., "204 No Content") into an error; verify if this is the desired behavior
|
||||
if response.statusCode != http.StatusOK {
|
||||
return nil, types.ContainerPathStat{}, fmt.Errorf("unexpected status code from daemon: %d", response.statusCode)
|
||||
}
|
||||
|
||||
+1
-5
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
@@ -43,14 +42,11 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
|
||||
}
|
||||
|
||||
serverResp, err := cli.post(ctx, "/containers/create", query, body, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
if serverResp.statusCode == 404 && strings.Contains(err.Error(), "No such image") {
|
||||
return response, objectNotFoundError{object: "image", id: config.Image}
|
||||
}
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(serverResp.body).Decode(&response)
|
||||
ensureReaderClosed(serverResp)
|
||||
return response, err
|
||||
}
|
||||
+1
-1
@@ -13,11 +13,11 @@ func (cli *Client) ContainerDiff(ctx context.Context, containerID string) ([]con
|
||||
var changes []container.ContainerChangeResponseItem
|
||||
|
||||
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return changes, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(serverResp.body).Decode(&changes)
|
||||
ensureReaderClosed(serverResp)
|
||||
return changes, err
|
||||
}
|
||||
+1
-1
@@ -16,11 +16,11 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, container string, co
|
||||
}
|
||||
|
||||
resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, config, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
err = json.NewDecoder(resp.body).Decode(&response)
|
||||
ensureReaderClosed(resp)
|
||||
return response, err
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -16,13 +16,13 @@ func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (ty
|
||||
return types.ContainerJSON{}, objectNotFoundError{object: "container", id: containerID}
|
||||
}
|
||||
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return types.ContainerJSON{}, wrapResponseError(err, serverResp, "container", containerID)
|
||||
}
|
||||
|
||||
var response types.ContainerJSON
|
||||
err = json.NewDecoder(serverResp.body).Decode(&response)
|
||||
ensureReaderClosed(serverResp)
|
||||
return response, err
|
||||
}
|
||||
|
||||
@@ -36,10 +36,10 @@ func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID stri
|
||||
query.Set("size", "1")
|
||||
}
|
||||
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return types.ContainerJSON{}, nil, wrapResponseError(err, serverResp, "container", containerID)
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
body, err := ioutil.ReadAll(serverResp.body)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -45,12 +45,12 @@ func (cli *Client) ContainerList(ctx context.Context, options types.ContainerLis
|
||||
}
|
||||
|
||||
resp, err := cli.get(ctx, "/containers/json", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var containers []types.Container
|
||||
err = json.NewDecoder(resp.body).Decode(&containers)
|
||||
ensureReaderClosed(resp)
|
||||
return containers, err
|
||||
}
|
||||
+1
-1
@@ -23,10 +23,10 @@ func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Arg
|
||||
}
|
||||
|
||||
serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return report, err
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||
return report, fmt.Errorf("Error retrieving disk usage: %v", err)
|
||||
|
||||
+1
-1
@@ -22,6 +22,6 @@ func (cli *Client) ContainerRemove(ctx context.Context, containerID string, opti
|
||||
}
|
||||
|
||||
resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil)
|
||||
ensureReaderClosed(resp)
|
||||
defer ensureReaderClosed(resp)
|
||||
return wrapResponseError(err, resp, "container", containerID)
|
||||
}
|
||||
+1
-1
@@ -18,11 +18,11 @@ func (cli *Client) ContainerTop(ctx context.Context, containerID string, argumen
|
||||
}
|
||||
|
||||
resp, err := cli.get(ctx, "/containers/"+containerID+"/top", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.body).Decode(&response)
|
||||
ensureReaderClosed(resp)
|
||||
return response, err
|
||||
}
|
||||
+1
-2
@@ -11,12 +11,11 @@ import (
|
||||
func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error) {
|
||||
var response container.ContainerUpdateOKBody
|
||||
serverResp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(serverResp.body).Decode(&response)
|
||||
|
||||
ensureReaderClosed(serverResp)
|
||||
return response, err
|
||||
}
|
||||
+1
-1
@@ -13,10 +13,10 @@ func (cli *Client) DiskUsage(ctx context.Context) (types.DiskUsage, error) {
|
||||
var du types.DiskUsage
|
||||
|
||||
serverResp, err := cli.get(ctx, "/system/df", nil, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return du, err
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
if err := json.NewDecoder(serverResp.body).Decode(&du); err != nil {
|
||||
return du, fmt.Errorf("Error retrieving disk usage: %v", err)
|
||||
|
||||
+1
-1
@@ -28,11 +28,11 @@ func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegist
|
||||
}
|
||||
|
||||
resp, err := cli.get(ctx, "/distribution/"+image+"/json", url.Values{}, headers)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return distributionInspect, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.body).Decode(&distributionInspect)
|
||||
ensureReaderClosed(resp)
|
||||
return distributionInspect, err
|
||||
}
|
||||
+17
-11
@@ -5,6 +5,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -32,16 +33,19 @@ func ErrorConnectionFailed(host string) error {
|
||||
return errConnectionFailed{host: host}
|
||||
}
|
||||
|
||||
// Deprecated: use the errdefs.NotFound() interface instead. Kept for backward compatibility
|
||||
type notFound interface {
|
||||
error
|
||||
NotFound() bool // Is the error a NotFound error
|
||||
NotFound() bool
|
||||
}
|
||||
|
||||
// IsErrNotFound returns true if the error is a NotFound error, which is returned
|
||||
// by the API when some object is not found.
|
||||
func IsErrNotFound(err error) bool {
|
||||
te, ok := err.(notFound)
|
||||
return ok && te.NotFound()
|
||||
if _, ok := err.(notFound); ok {
|
||||
return ok
|
||||
}
|
||||
return errdefs.IsNotFound(err)
|
||||
}
|
||||
|
||||
type objectNotFoundError struct {
|
||||
@@ -49,9 +53,7 @@ type objectNotFoundError struct {
|
||||
id string
|
||||
}
|
||||
|
||||
func (e objectNotFoundError) NotFound() bool {
|
||||
return true
|
||||
}
|
||||
func (e objectNotFoundError) NotFound() {}
|
||||
|
||||
func (e objectNotFoundError) Error() string {
|
||||
return fmt.Sprintf("Error: No such %s: %s", e.object, e.id)
|
||||
@@ -64,7 +66,7 @@ func wrapResponseError(err error, resp serverResponse, object, id string) error
|
||||
case resp.statusCode == http.StatusNotFound:
|
||||
return objectNotFoundError{object: object, id: id}
|
||||
case resp.statusCode == http.StatusNotImplemented:
|
||||
return notImplementedError{message: err.Error()}
|
||||
return errdefs.NotImplemented(err)
|
||||
default:
|
||||
return err
|
||||
}
|
||||
@@ -83,8 +85,10 @@ func (u unauthorizedError) Error() string {
|
||||
// IsErrUnauthorized returns true if the error is caused
|
||||
// when a remote registry authentication fails
|
||||
func IsErrUnauthorized(err error) bool {
|
||||
_, ok := err.(unauthorizedError)
|
||||
return ok
|
||||
if _, ok := err.(unauthorizedError); ok {
|
||||
return ok
|
||||
}
|
||||
return errdefs.IsUnauthorized(err)
|
||||
}
|
||||
|
||||
type pluginPermissionDenied struct {
|
||||
@@ -118,8 +122,10 @@ func (e notImplementedError) NotImplemented() bool {
|
||||
// This is returned by the API when a requested feature has not been
|
||||
// implemented.
|
||||
func IsErrNotImplemented(err error) bool {
|
||||
te, ok := err.(notImplementedError)
|
||||
return ok && te.NotImplemented()
|
||||
if _, ok := err.(notImplementedError); ok {
|
||||
return ok
|
||||
}
|
||||
return errdefs.IsNotImplemented(err)
|
||||
}
|
||||
|
||||
// NewVersionError returns an error if the APIVersion required
|
||||
|
||||
+12
-1
@@ -23,7 +23,7 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
|
||||
return types.HijackedResponse{}, err
|
||||
}
|
||||
|
||||
apiPath := cli.getAPIPath(path, query)
|
||||
apiPath := cli.getAPIPath(ctx, path, query)
|
||||
req, err := http.NewRequest("POST", apiPath, bodyEncoded)
|
||||
if err != nil {
|
||||
return types.HijackedResponse{}, err
|
||||
@@ -38,6 +38,17 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
|
||||
return types.HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn)}, err
|
||||
}
|
||||
|
||||
// DialHijack returns a hijacked connection with negotiated protocol proto.
|
||||
func (cli *Client) DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error) {
|
||||
req, err := http.NewRequest("POST", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req = cli.addHeaders(req, meta)
|
||||
|
||||
return cli.setupHijackConn(ctx, req, proto)
|
||||
}
|
||||
|
||||
// fallbackDial is used when WithDialer() was not called.
|
||||
// See cli.Dialer().
|
||||
func fallbackDial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) {
|
||||
|
||||
+8
@@ -134,5 +134,13 @@ func (cli *Client) imageBuildOptionsToQuery(options types.ImageBuildOptions) (ur
|
||||
query.Set("buildid", options.BuildID)
|
||||
}
|
||||
query.Set("version", string(options.Version))
|
||||
|
||||
if options.Outputs != nil {
|
||||
outputsJSON, err := json.Marshal(options.Outputs)
|
||||
if err != nil {
|
||||
return query, err
|
||||
}
|
||||
query.Set("outputs", string(outputsJSON))
|
||||
}
|
||||
return query, nil
|
||||
}
|
||||
+1
-1
@@ -12,11 +12,11 @@ import (
|
||||
func (cli *Client) ImageHistory(ctx context.Context, imageID string) ([]image.HistoryResponseItem, error) {
|
||||
var history []image.HistoryResponseItem
|
||||
serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", url.Values{}, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return history, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(serverResp.body).Decode(&history)
|
||||
ensureReaderClosed(serverResp)
|
||||
return history, err
|
||||
}
|
||||
+1
-1
@@ -15,10 +15,10 @@ func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (typ
|
||||
return types.ImageInspect{}, nil, objectNotFoundError{object: "image", id: imageID}
|
||||
}
|
||||
serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", nil, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return types.ImageInspect{}, nil, wrapResponseError(err, serverResp, "image", imageID)
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
body, err := ioutil.ReadAll(serverResp.body)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -35,11 +35,11 @@ func (cli *Client) ImageList(ctx context.Context, options types.ImageListOptions
|
||||
}
|
||||
|
||||
serverResp, err := cli.get(ctx, "/images/json", query, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return images, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(serverResp.body).Decode(&images)
|
||||
ensureReaderClosed(serverResp)
|
||||
return images, err
|
||||
}
|
||||
+1
-1
@@ -23,10 +23,10 @@ func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (
|
||||
}
|
||||
|
||||
serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return report, err
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||
return report, fmt.Errorf("Error retrieving disk usage: %v", err)
|
||||
|
||||
+2
-2
@@ -3,12 +3,12 @@ package client // import "github.com/docker/docker/client"
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/errdefs"
|
||||
)
|
||||
|
||||
// ImagePull requests the docker host to pull an image from a remote registry.
|
||||
@@ -35,7 +35,7 @@ func (cli *Client) ImagePull(ctx context.Context, refStr string, options types.I
|
||||
}
|
||||
|
||||
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
|
||||
if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil {
|
||||
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
|
||||
newAuthHeader, privilegeErr := options.PrivilegeFunc()
|
||||
if privilegeErr != nil {
|
||||
return nil, privilegeErr
|
||||
|
||||
+2
-2
@@ -4,11 +4,11 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/errdefs"
|
||||
)
|
||||
|
||||
// ImagePush requests the docker host to push an image to a remote registry.
|
||||
@@ -36,7 +36,7 @@ func (cli *Client) ImagePush(ctx context.Context, image string, options types.Im
|
||||
query.Set("tag", tag)
|
||||
|
||||
resp, err := cli.tryImagePush(ctx, name, query, options.RegistryAuth)
|
||||
if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil {
|
||||
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
|
||||
newAuthHeader, privilegeErr := options.PrivilegeFunc()
|
||||
if privilegeErr != nil {
|
||||
return nil, privilegeErr
|
||||
|
||||
+1
-1
@@ -21,11 +21,11 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options type
|
||||
|
||||
var dels []types.ImageDeleteResponseItem
|
||||
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return dels, wrapResponseError(err, resp, "image", imageID)
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.body).Decode(&dels)
|
||||
ensureReaderClosed(resp)
|
||||
return dels, err
|
||||
}
|
||||
+3
-3
@@ -4,12 +4,12 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/errdefs"
|
||||
)
|
||||
|
||||
// ImageSearch makes the docker host to search by a term in a remote registry.
|
||||
@@ -29,7 +29,8 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I
|
||||
}
|
||||
|
||||
resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth)
|
||||
if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil {
|
||||
defer ensureReaderClosed(resp)
|
||||
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
|
||||
newAuthHeader, privilegeErr := options.PrivilegeFunc()
|
||||
if privilegeErr != nil {
|
||||
return results, privilegeErr
|
||||
@@ -41,7 +42,6 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.body).Decode(&results)
|
||||
ensureReaderClosed(resp)
|
||||
return results, err
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -13,10 +13,10 @@ import (
|
||||
func (cli *Client) Info(ctx context.Context) (types.Info, error) {
|
||||
var info types.Info
|
||||
serverResp, err := cli.get(ctx, "/info", url.Values{}, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return info, err
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
if err := json.NewDecoder(serverResp.body).Decode(&info); err != nil {
|
||||
return info, fmt.Errorf("Error reading remote info: %v", err)
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ type CommonAPIClient interface {
|
||||
ServerVersion(ctx context.Context) (types.Version, error)
|
||||
NegotiateAPIVersion(ctx context.Context)
|
||||
NegotiateAPIVersionPing(types.Ping)
|
||||
DialSession(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error)
|
||||
DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error)
|
||||
Dialer() func(context.Context) (net.Conn, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
+1
-5
@@ -3,7 +3,6 @@ package client // import "github.com/docker/docker/client"
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
@@ -14,16 +13,13 @@ import (
|
||||
// It returns unauthorizedError when the authentication fails.
|
||||
func (cli *Client) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, error) {
|
||||
resp, err := cli.post(ctx, "/auth", url.Values{}, auth, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
|
||||
if resp.statusCode == http.StatusUnauthorized {
|
||||
return registry.AuthenticateOKBody{}, unauthorizedError{err}
|
||||
}
|
||||
if err != nil {
|
||||
return registry.AuthenticateOKBody{}, err
|
||||
}
|
||||
|
||||
var response registry.AuthenticateOKBody
|
||||
err = json.NewDecoder(resp.body).Decode(&response)
|
||||
ensureReaderClosed(resp)
|
||||
return response, err
|
||||
}
|
||||
+2
-2
@@ -15,11 +15,11 @@ func (cli *Client) NetworkCreate(ctx context.Context, name string, options types
|
||||
}
|
||||
var response types.NetworkCreateResponse
|
||||
serverResp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
json.NewDecoder(serverResp.body).Decode(&response)
|
||||
ensureReaderClosed(serverResp)
|
||||
err = json.NewDecoder(serverResp.body).Decode(&response)
|
||||
return response, err
|
||||
}
|
||||
+1
-1
@@ -34,10 +34,10 @@ func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string,
|
||||
query.Set("scope", options.Scope)
|
||||
}
|
||||
resp, err = cli.get(ctx, "/networks/"+networkID, query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return networkResource, nil, wrapResponseError(err, resp, "network", networkID)
|
||||
}
|
||||
defer ensureReaderClosed(resp)
|
||||
|
||||
body, err := ioutil.ReadAll(resp.body)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -22,10 +22,10 @@ func (cli *Client) NetworkList(ctx context.Context, options types.NetworkListOpt
|
||||
}
|
||||
var networkResources []types.NetworkResource
|
||||
resp, err := cli.get(ctx, "/networks", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return networkResources, err
|
||||
}
|
||||
err = json.NewDecoder(resp.body).Decode(&networkResources)
|
||||
ensureReaderClosed(resp)
|
||||
return networkResources, err
|
||||
}
|
||||
+1
-1
@@ -23,10 +23,10 @@ func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args)
|
||||
}
|
||||
|
||||
serverResp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return report, err
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||
return report, fmt.Errorf("Error retrieving network prune report: %v", err)
|
||||
|
||||
+1
-1
@@ -5,6 +5,6 @@ import "context"
|
||||
// NetworkRemove removes an existent network from the docker host.
|
||||
func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error {
|
||||
resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil)
|
||||
ensureReaderClosed(resp)
|
||||
defer ensureReaderClosed(resp)
|
||||
return wrapResponseError(err, resp, "network", networkID)
|
||||
}
|
||||
+1
-1
@@ -15,10 +15,10 @@ func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm
|
||||
return swarm.Node{}, nil, objectNotFoundError{object: "node", id: nodeID}
|
||||
}
|
||||
serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return swarm.Node{}, nil, wrapResponseError(err, serverResp, "node", nodeID)
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
body, err := ioutil.ReadAll(serverResp.body)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -25,12 +25,12 @@ func (cli *Client) NodeList(ctx context.Context, options types.NodeListOptions)
|
||||
}
|
||||
|
||||
resp, err := cli.get(ctx, "/nodes", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var nodes []swarm.Node
|
||||
err = json.NewDecoder(resp.body).Decode(&nodes)
|
||||
ensureReaderClosed(resp)
|
||||
return nodes, err
|
||||
}
|
||||
+1
-1
@@ -15,6 +15,6 @@ func (cli *Client) NodeRemove(ctx context.Context, nodeID string, options types.
|
||||
}
|
||||
|
||||
resp, err := cli.delete(ctx, "/nodes/"+nodeID, query, nil)
|
||||
ensureReaderClosed(resp)
|
||||
defer ensureReaderClosed(resp)
|
||||
return wrapResponseError(err, resp, "node", nodeID)
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-connections/sockets"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Opt is a configuration option to initialize a client
|
||||
type Opt func(*Client) error
|
||||
|
||||
// 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 != "" {
|
||||
options := tlsconfig.Options{
|
||||
CAFile: filepath.Join(dockerCertPath, "ca.pem"),
|
||||
CertFile: filepath.Join(dockerCertPath, "cert.pem"),
|
||||
KeyFile: filepath.Join(dockerCertPath, "key.pem"),
|
||||
InsecureSkipVerify: os.Getenv("DOCKER_TLS_VERIFY") == "",
|
||||
}
|
||||
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 != "" {
|
||||
if err := WithVersion(version)(c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithDialer applies the dialer.DialContext to the client transport. This can be
|
||||
// used to set the Timeout and KeepAlive settings of the client.
|
||||
// Deprecated: use WithDialContext
|
||||
func WithDialer(dialer *net.Dialer) Opt {
|
||||
return WithDialContext(dialer.DialContext)
|
||||
}
|
||||
|
||||
// WithDialContext applies the dialer to the client transport. This can be
|
||||
// used to set the Timeout and KeepAlive settings of the client.
|
||||
func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) Opt {
|
||||
return func(c *Client) error {
|
||||
if transport, ok := c.client.Transport.(*http.Transport); ok {
|
||||
transport.DialContext = dialContext
|
||||
return nil
|
||||
}
|
||||
return errors.Errorf("cannot apply dialer to transport: %T", c.client.Transport)
|
||||
}
|
||||
}
|
||||
|
||||
// WithHost overrides the client host with the specified one.
|
||||
func WithHost(host string) Opt {
|
||||
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) Opt {
|
||||
return func(c *Client) error {
|
||||
if client != nil {
|
||||
c.client = client
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithTimeout configures the time limit for requests made by the HTTP client
|
||||
func WithTimeout(timeout time.Duration) Opt {
|
||||
return func(c *Client) error {
|
||||
c.client.Timeout = timeout
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPHeaders overrides the client default http headers
|
||||
func WithHTTPHeaders(headers map[string]string) Opt {
|
||||
return func(c *Client) error {
|
||||
c.customHTTPHeaders = headers
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithScheme overrides the client scheme with the specified one
|
||||
func WithScheme(scheme string) Opt {
|
||||
return func(c *Client) error {
|
||||
c.scheme = scheme
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithTLSClientConfig applies a tls config to the client transport.
|
||||
func WithTLSClientConfig(cacertPath, certPath, keyPath string) Opt {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// WithVersion overrides the client version with the specified one. If an empty
|
||||
// version is specified, the value will be ignored to allow version negotiation.
|
||||
func WithVersion(version string) Opt {
|
||||
return func(c *Client) error {
|
||||
if version != "" {
|
||||
c.version = version
|
||||
c.manualOverride = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithAPIVersionNegotiation enables automatic API version negotiation for the client.
|
||||
// With this option enabled, the client automatically negotiates the API version
|
||||
// to use when making requests. API version negotiation is performed on the first
|
||||
// request; subsequent requests will not re-negotiate.
|
||||
func WithAPIVersionNegotiation() Opt {
|
||||
return func(c *Client) error {
|
||||
c.negotiateVersion = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
+45
-14
@@ -2,34 +2,65 @@ package client // import "github.com/docker/docker/client"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/errdefs"
|
||||
)
|
||||
|
||||
// Ping pings the server and returns the value of the "Docker-Experimental", "Builder-Version", "OS-Type" & "API-Version" headers
|
||||
// Ping pings the server and returns the value of the "Docker-Experimental",
|
||||
// "Builder-Version", "OS-Type" & "API-Version" headers. It attempts to use
|
||||
// a HEAD request on the endpoint, but falls back to GET if HEAD is not supported
|
||||
// by the daemon.
|
||||
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
|
||||
var ping types.Ping
|
||||
req, err := cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil)
|
||||
|
||||
// Using cli.buildRequest() + cli.doRequest() instead of cli.sendRequest()
|
||||
// because ping requests are used during API version negotiation, so we want
|
||||
// to hit the non-versioned /_ping endpoint, not /v1.xx/_ping
|
||||
req, err := cli.buildRequest("HEAD", path.Join(cli.basePath, "/_ping"), nil, nil)
|
||||
if err != nil {
|
||||
return ping, err
|
||||
}
|
||||
serverResp, err := cli.doRequest(ctx, req)
|
||||
if err == nil {
|
||||
defer ensureReaderClosed(serverResp)
|
||||
switch serverResp.statusCode {
|
||||
case http.StatusOK, http.StatusInternalServerError:
|
||||
// Server handled the request, so parse the response
|
||||
return parsePingResponse(cli, serverResp)
|
||||
}
|
||||
} else if IsErrConnectionFailed(err) {
|
||||
return ping, err
|
||||
}
|
||||
|
||||
req, err = cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil)
|
||||
if err != nil {
|
||||
return ping, err
|
||||
}
|
||||
serverResp, err = cli.doRequest(ctx, req)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
if serverResp.header != nil {
|
||||
ping.APIVersion = serverResp.header.Get("API-Version")
|
||||
|
||||
if serverResp.header.Get("Docker-Experimental") == "true" {
|
||||
ping.Experimental = true
|
||||
}
|
||||
ping.OSType = serverResp.header.Get("OSType")
|
||||
if bv := serverResp.header.Get("Builder-Version"); bv != "" {
|
||||
ping.BuilderVersion = types.BuilderVersion(bv)
|
||||
}
|
||||
if err != nil {
|
||||
return ping, err
|
||||
}
|
||||
return ping, cli.checkResponseErr(serverResp)
|
||||
return parsePingResponse(cli, serverResp)
|
||||
}
|
||||
|
||||
func parsePingResponse(cli *Client, resp serverResponse) (types.Ping, error) {
|
||||
var ping types.Ping
|
||||
if resp.header == nil {
|
||||
err := cli.checkResponseErr(resp)
|
||||
return ping, errdefs.FromStatusCode(err, resp.statusCode)
|
||||
}
|
||||
ping.APIVersion = resp.header.Get("API-Version")
|
||||
ping.OSType = resp.header.Get("OSType")
|
||||
if resp.header.Get("Docker-Experimental") == "true" {
|
||||
ping.Experimental = true
|
||||
}
|
||||
if bv := resp.header.Get("Builder-Version"); bv != "" {
|
||||
ping.BuilderVersion = types.BuilderVersion(bv)
|
||||
}
|
||||
err := cli.checkResponseErr(resp)
|
||||
return ping, errdefs.FromStatusCode(err, resp.statusCode)
|
||||
}
|
||||
-3
@@ -18,9 +18,6 @@ func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, cr
|
||||
query.Set("name", createOptions.RepoName)
|
||||
|
||||
resp, err := cli.postRaw(ctx, "/plugins/create", query, createContext, headers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ensureReaderClosed(resp)
|
||||
return err
|
||||
}
|
||||
+1
-1
@@ -15,11 +15,11 @@ func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*type
|
||||
return nil, nil, objectNotFoundError{object: "plugin", id: name}
|
||||
}
|
||||
resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return nil, nil, wrapResponseError(err, resp, "plugin", name)
|
||||
}
|
||||
|
||||
defer ensureReaderClosed(resp)
|
||||
body, err := ioutil.ReadAll(resp.body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
+2
-2
@@ -4,11 +4,11 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -78,7 +78,7 @@ func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileg
|
||||
|
||||
func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options types.PluginInstallOptions) (types.PluginPrivileges, error) {
|
||||
resp, err := cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
|
||||
if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil {
|
||||
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
|
||||
// todo: do inspect before to check existing name before checking privileges
|
||||
newAuthHeader, privilegeErr := options.PrivilegeFunc()
|
||||
if privilegeErr != nil {
|
||||
|
||||
+1
-1
@@ -22,11 +22,11 @@ func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (types.P
|
||||
query.Set("filters", filterJSON)
|
||||
}
|
||||
resp, err := cli.get(ctx, "/plugins", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return plugins, wrapResponseError(err, resp, "plugin", "")
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.body).Decode(&plugins)
|
||||
ensureReaderClosed(resp)
|
||||
return plugins, err
|
||||
}
|
||||
+1
-1
@@ -15,6 +15,6 @@ func (cli *Client) PluginRemove(ctx context.Context, name string, options types.
|
||||
}
|
||||
|
||||
resp, err := cli.delete(ctx, "/plugins/"+name, query, nil)
|
||||
ensureReaderClosed(resp)
|
||||
defer ensureReaderClosed(resp)
|
||||
return wrapResponseError(err, resp, "plugin", name)
|
||||
}
|
||||
+34
-14
@@ -15,8 +15,8 @@ import (
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
)
|
||||
|
||||
// serverResponse is a wrapper for http API responses.
|
||||
@@ -115,28 +115,30 @@ func (cli *Client) buildRequest(method, path string, body io.Reader, headers hea
|
||||
}
|
||||
|
||||
func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers headers) (serverResponse, error) {
|
||||
req, err := cli.buildRequest(method, cli.getAPIPath(path, query), body, headers)
|
||||
req, err := cli.buildRequest(method, cli.getAPIPath(ctx, path, query), body, headers)
|
||||
if err != nil {
|
||||
return serverResponse{}, err
|
||||
}
|
||||
resp, err := cli.doRequest(ctx, req)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
return resp, errdefs.FromStatusCode(err, resp.statusCode)
|
||||
}
|
||||
return resp, cli.checkResponseErr(resp)
|
||||
err = cli.checkResponseErr(resp)
|
||||
return resp, errdefs.FromStatusCode(err, resp.statusCode)
|
||||
}
|
||||
|
||||
func (cli *Client) doRequest(ctx context.Context, req *http.Request) (serverResponse, error) {
|
||||
serverResp := serverResponse{statusCode: -1, reqURL: req.URL}
|
||||
|
||||
resp, err := ctxhttp.Do(ctx, cli.client, req)
|
||||
req = req.WithContext(ctx)
|
||||
resp, err := cli.client.Do(req)
|
||||
if err != nil {
|
||||
if cli.scheme != "https" && strings.Contains(err.Error(), "malformed HTTP response") {
|
||||
return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)
|
||||
}
|
||||
|
||||
if cli.scheme == "https" && strings.Contains(err.Error(), "bad certificate") {
|
||||
return serverResp, fmt.Errorf("The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings: %v", err)
|
||||
return serverResp, errors.Wrap(err, "The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings")
|
||||
}
|
||||
|
||||
// Don't decorate context sentinel errors; users may be comparing to
|
||||
@@ -176,7 +178,13 @@ func (cli *Client) doRequest(ctx context.Context, req *http.Request) (serverResp
|
||||
// this is localised - for example in French the error would be
|
||||
// `open //./pipe/docker_engine: Le fichier spécifié est introuvable.`
|
||||
if strings.Contains(err.Error(), `open //./pipe/docker_engine`) {
|
||||
err = errors.New(err.Error() + " In the default daemon configuration on Windows, the docker client must be run elevated to connect. This error may also indicate that the docker daemon is not running.")
|
||||
// Checks if client is running with elevated privileges
|
||||
if f, elevatedErr := os.Open("\\\\.\\PHYSICALDRIVE0"); elevatedErr == nil {
|
||||
err = errors.Wrap(err, "In the default daemon configuration on Windows, the docker client must be run with elevated privileges to connect.")
|
||||
} else {
|
||||
f.Close()
|
||||
err = errors.Wrap(err, "This error may indicate that the docker daemon is not running.")
|
||||
}
|
||||
}
|
||||
|
||||
return serverResp, errors.Wrap(err, "error during connect")
|
||||
@@ -195,9 +203,21 @@ func (cli *Client) checkResponseErr(serverResp serverResponse) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(serverResp.body)
|
||||
if err != nil {
|
||||
return err
|
||||
var body []byte
|
||||
var err error
|
||||
if serverResp.body != nil {
|
||||
bodyMax := 1 * 1024 * 1024 // 1 MiB
|
||||
bodyR := &io.LimitedReader{
|
||||
R: serverResp.body,
|
||||
N: int64(bodyMax),
|
||||
}
|
||||
body, err = ioutil.ReadAll(bodyR)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if bodyR.N == 0 {
|
||||
return fmt.Errorf("request returned %s with a message (> %d bytes) for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), bodyMax, serverResp.reqURL)
|
||||
}
|
||||
}
|
||||
if len(body) == 0 {
|
||||
return fmt.Errorf("request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), serverResp.reqURL)
|
||||
@@ -212,14 +232,14 @@ func (cli *Client) checkResponseErr(serverResp serverResponse) error {
|
||||
if (cli.version == "" || versions.GreaterThan(cli.version, "1.23")) && ct == "application/json" {
|
||||
var errorResponse types.ErrorResponse
|
||||
if err := json.Unmarshal(body, &errorResponse); err != nil {
|
||||
return fmt.Errorf("Error reading JSON: %v", err)
|
||||
return errors.Wrap(err, "Error reading JSON")
|
||||
}
|
||||
errorMessage = errorResponse.Message
|
||||
errorMessage = strings.TrimSpace(errorResponse.Message)
|
||||
} else {
|
||||
errorMessage = string(body)
|
||||
errorMessage = strings.TrimSpace(string(body))
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error response from daemon: %s", strings.TrimSpace(errorMessage))
|
||||
return errors.Wrap(errors.New(errorMessage), "Error response from daemon")
|
||||
}
|
||||
|
||||
func (cli *Client) addHeaders(req *http.Request, headers headers) *http.Request {
|
||||
|
||||
+1
-1
@@ -15,11 +15,11 @@ func (cli *Client) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (t
|
||||
return response, err
|
||||
}
|
||||
resp, err := cli.post(ctx, "/secrets/create", nil, secret, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.body).Decode(&response)
|
||||
ensureReaderClosed(resp)
|
||||
return response, err
|
||||
}
|
||||
+1
-1
@@ -18,10 +18,10 @@ func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.S
|
||||
return swarm.Secret{}, nil, objectNotFoundError{object: "secret", id: id}
|
||||
}
|
||||
resp, err := cli.get(ctx, "/secrets/"+id, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return swarm.Secret{}, nil, wrapResponseError(err, resp, "secret", id)
|
||||
}
|
||||
defer ensureReaderClosed(resp)
|
||||
|
||||
body, err := ioutil.ReadAll(resp.body)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -27,12 +27,12 @@ func (cli *Client) SecretList(ctx context.Context, options types.SecretListOptio
|
||||
}
|
||||
|
||||
resp, err := cli.get(ctx, "/secrets", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var secrets []swarm.Secret
|
||||
err = json.NewDecoder(resp.body).Decode(&secrets)
|
||||
ensureReaderClosed(resp)
|
||||
return secrets, err
|
||||
}
|
||||
+1
-1
@@ -8,6 +8,6 @@ func (cli *Client) SecretRemove(ctx context.Context, id string) error {
|
||||
return err
|
||||
}
|
||||
resp, err := cli.delete(ctx, "/secrets/"+id, nil, nil)
|
||||
ensureReaderClosed(resp)
|
||||
defer ensureReaderClosed(resp)
|
||||
return wrapResponseError(err, resp, "secret", id)
|
||||
}
|
||||
+1
-1
@@ -72,6 +72,7 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
|
||||
|
||||
var response types.ServiceCreateResponse
|
||||
resp, err := cli.post(ctx, "/services/create", nil, service, headers)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
@@ -82,7 +83,6 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
|
||||
response.Warnings = append(response.Warnings, digestWarning(service.TaskTemplate.ContainerSpec.Image))
|
||||
}
|
||||
|
||||
ensureReaderClosed(resp)
|
||||
return response, err
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -20,10 +20,10 @@ func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string,
|
||||
query := url.Values{}
|
||||
query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults))
|
||||
serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return swarm.Service{}, nil, wrapResponseError(err, serverResp, "service", serviceID)
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
body, err := ioutil.ReadAll(serverResp.body)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -24,12 +24,12 @@ func (cli *Client) ServiceList(ctx context.Context, options types.ServiceListOpt
|
||||
}
|
||||
|
||||
resp, err := cli.get(ctx, "/services", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var services []swarm.Service
|
||||
err = json.NewDecoder(resp.body).Decode(&services)
|
||||
ensureReaderClosed(resp)
|
||||
return services, err
|
||||
}
|
||||
+1
-1
@@ -5,6 +5,6 @@ import "context"
|
||||
// ServiceRemove kills and removes a service.
|
||||
func (cli *Client) ServiceRemove(ctx context.Context, serviceID string) error {
|
||||
resp, err := cli.delete(ctx, "/services/"+serviceID, nil, nil)
|
||||
ensureReaderClosed(resp)
|
||||
defer ensureReaderClosed(resp)
|
||||
return wrapResponseError(err, resp, "service", serviceID)
|
||||
}
|
||||
+4
-2
@@ -10,7 +10,9 @@ import (
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
)
|
||||
|
||||
// ServiceUpdate updates a Service.
|
||||
// ServiceUpdate updates a Service. The version number is required to avoid conflicting writes.
|
||||
// It should be the value as set *before* the update. You can find this value in the Meta field
|
||||
// of swarm.Service, which can be found using ServiceInspectWithRaw.
|
||||
func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) {
|
||||
var (
|
||||
query = url.Values{}
|
||||
@@ -77,6 +79,7 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
|
||||
|
||||
var response types.ServiceUpdateResponse
|
||||
resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, service, headers)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
@@ -87,6 +90,5 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
|
||||
response.Warnings = append(response.Warnings, digestWarning(service.TaskTemplate.ContainerSpec.Image))
|
||||
}
|
||||
|
||||
ensureReaderClosed(resp)
|
||||
return response, err
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
package client // import "github.com/docker/docker/client"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// DialSession returns a connection that can be used communication with daemon
|
||||
func (cli *Client) DialSession(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) {
|
||||
req, err := http.NewRequest("POST", "/session", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req = cli.addHeaders(req, meta)
|
||||
|
||||
return cli.setupHijackConn(ctx, req, proto)
|
||||
}
|
||||
+1
-1
@@ -10,12 +10,12 @@ import (
|
||||
// SwarmGetUnlockKey retrieves the swarm's unlock key.
|
||||
func (cli *Client) SwarmGetUnlockKey(ctx context.Context) (types.SwarmUnlockKeyResponse, error) {
|
||||
serverResp, err := cli.get(ctx, "/swarm/unlockkey", nil, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return types.SwarmUnlockKeyResponse{}, err
|
||||
}
|
||||
|
||||
var response types.SwarmUnlockKeyResponse
|
||||
err = json.NewDecoder(serverResp.body).Decode(&response)
|
||||
ensureReaderClosed(serverResp)
|
||||
return response, err
|
||||
}
|
||||
+1
-1
@@ -10,12 +10,12 @@ import (
|
||||
// SwarmInit initializes the swarm.
|
||||
func (cli *Client) SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) {
|
||||
serverResp, err := cli.post(ctx, "/swarm/init", nil, req, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var response string
|
||||
err = json.NewDecoder(serverResp.body).Decode(&response)
|
||||
ensureReaderClosed(serverResp)
|
||||
return response, err
|
||||
}
|
||||
+1
-1
@@ -10,12 +10,12 @@ import (
|
||||
// SwarmInspect inspects the swarm.
|
||||
func (cli *Client) SwarmInspect(ctx context.Context) (swarm.Swarm, error) {
|
||||
serverResp, err := cli.get(ctx, "/swarm", nil, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return swarm.Swarm{}, err
|
||||
}
|
||||
|
||||
var response swarm.Swarm
|
||||
err = json.NewDecoder(serverResp.body).Decode(&response)
|
||||
ensureReaderClosed(serverResp)
|
||||
return response, err
|
||||
}
|
||||
+1
-1
@@ -15,10 +15,10 @@ func (cli *Client) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm
|
||||
return swarm.Task{}, nil, objectNotFoundError{object: "task", id: taskID}
|
||||
}
|
||||
serverResp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
if err != nil {
|
||||
return swarm.Task{}, nil, wrapResponseError(err, serverResp, "task", taskID)
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
body, err := ioutil.ReadAll(serverResp.body)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -24,12 +24,12 @@ func (cli *Client) TaskList(ctx context.Context, options types.TaskListOptions)
|
||||
}
|
||||
|
||||
resp, err := cli.get(ctx, "/tasks", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tasks []swarm.Task
|
||||
err = json.NewDecoder(resp.body).Decode(&tasks)
|
||||
ensureReaderClosed(resp)
|
||||
return tasks, err
|
||||
}
|
||||
+1
-1
@@ -10,12 +10,12 @@ import (
|
||||
// ServerVersion returns information of the docker client and server host.
|
||||
func (cli *Client) ServerVersion(ctx context.Context) (types.Version, error) {
|
||||
resp, err := cli.get(ctx, "/version", nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return types.Version{}, err
|
||||
}
|
||||
|
||||
var server types.Version
|
||||
err = json.NewDecoder(resp.body).Decode(&server)
|
||||
ensureReaderClosed(resp)
|
||||
return server, err
|
||||
}
|
||||
+1
-1
@@ -12,10 +12,10 @@ import (
|
||||
func (cli *Client) VolumeCreate(ctx context.Context, options volumetypes.VolumeCreateBody) (types.Volume, error) {
|
||||
var volume types.Volume
|
||||
resp, err := cli.post(ctx, "/volumes/create", nil, options, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return volume, err
|
||||
}
|
||||
err = json.NewDecoder(resp.body).Decode(&volume)
|
||||
ensureReaderClosed(resp)
|
||||
return volume, err
|
||||
}
|
||||
+1
-1
@@ -23,10 +23,10 @@ func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (t
|
||||
|
||||
var volume types.Volume
|
||||
resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return volume, nil, wrapResponseError(err, resp, "volume", volumeID)
|
||||
}
|
||||
defer ensureReaderClosed(resp)
|
||||
|
||||
body, err := ioutil.ReadAll(resp.body)
|
||||
if err != nil {
|
||||
|
||||
Loaded 100 of 463 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user