mirror of https://github.com/docker/docs.git
Return registy status code in error
Added Details map to the JSONMessage
This commit is contained in:
parent
d5a57a4b5e
commit
3043c26419
12
api.go
12
api.go
|
@ -388,7 +388,7 @@ func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *ht
|
||||||
if image != "" { //pull
|
if image != "" { //pull
|
||||||
if err := srv.ImagePull(image, tag, w, sf, &auth.AuthConfig{}); err != nil {
|
if err := srv.ImagePull(image, tag, w, sf, &auth.AuthConfig{}); err != nil {
|
||||||
if sf.Used() {
|
if sf.Used() {
|
||||||
w.Write(sf.FormatError(err))
|
w.Write(sf.FormatError(err, 0))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -396,7 +396,7 @@ func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *ht
|
||||||
} else { //import
|
} else { //import
|
||||||
if err := srv.ImageImport(src, repo, tag, r.Body, w, sf); err != nil {
|
if err := srv.ImageImport(src, repo, tag, r.Body, w, sf); err != nil {
|
||||||
if sf.Used() {
|
if sf.Used() {
|
||||||
w.Write(sf.FormatError(err))
|
w.Write(sf.FormatError(err, 0))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -441,7 +441,7 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht
|
||||||
imgID, err := srv.ImageInsert(name, url, path, w, sf)
|
imgID, err := srv.ImageInsert(name, url, path, w, sf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if sf.Used() {
|
if sf.Used() {
|
||||||
w.Write(sf.FormatError(err))
|
w.Write(sf.FormatError(err, 0))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -472,7 +472,11 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http
|
||||||
sf := utils.NewStreamFormatter(version > 1.0)
|
sf := utils.NewStreamFormatter(version > 1.0)
|
||||||
if err := srv.ImagePush(name, w, sf, authConfig); err != nil {
|
if err := srv.ImagePush(name, w, sf, authConfig); err != nil {
|
||||||
if sf.Used() {
|
if sf.Used() {
|
||||||
w.Write(sf.FormatError(err))
|
var code int
|
||||||
|
if httpErr, ok := err.(*utils.HTTPRequestError); ok {
|
||||||
|
code = httpErr.StatusCode
|
||||||
|
}
|
||||||
|
w.Write(sf.FormatError(err, code))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
|
21
commands.go
21
commands.go
|
@ -31,6 +31,7 @@ const VERSION = "0.5.0-dev"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
GITCOMMIT string
|
GITCOMMIT string
|
||||||
|
AuthRequiredError error = fmt.Errorf("Authentication is required.")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) {
|
func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) {
|
||||||
|
@ -814,10 +815,6 @@ func (cli *DockerCli) CmdPush(args ...string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cli.checkIfLogged("push"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're not using a custom registry, we know the restrictions
|
// If we're not using a custom registry, we know the restrictions
|
||||||
// applied to repository names and can warn the user in advance.
|
// applied to repository names and can warn the user in advance.
|
||||||
// Custom repositories can have different rules, and we must also
|
// Custom repositories can have different rules, and we must also
|
||||||
|
@ -826,13 +823,22 @@ func (cli *DockerCli) CmdPush(args ...string) error {
|
||||||
return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.configFile.Configs[auth.IndexServerAddress()].Username, name)
|
return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.configFile.Configs[auth.IndexServerAddress()].Username, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v := url.Values{}
|
||||||
|
push := func() error {
|
||||||
buf, err := json.Marshal(cli.configFile.Configs[auth.IndexServerAddress()])
|
buf, err := json.Marshal(cli.configFile.Configs[auth.IndexServerAddress()])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
v := url.Values{}
|
return cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), bytes.NewBuffer(buf), cli.out)
|
||||||
if err := cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), bytes.NewBuffer(buf), cli.out); err != nil {
|
}
|
||||||
|
|
||||||
|
if err := push(); err != nil {
|
||||||
|
if err == AuthRequiredError {
|
||||||
|
if err = cli.checkIfLogged("push"); err == nil {
|
||||||
|
return push()
|
||||||
|
}
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -1559,6 +1565,9 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if jm.Error != nil && jm.Error.Code == 401 {
|
||||||
|
return AuthRequiredError
|
||||||
|
}
|
||||||
jm.Display(out)
|
jm.Display(out)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -147,7 +147,7 @@ func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]s
|
||||||
res, err := doWithCookies(r.client, req)
|
res, err := doWithCookies(r.client, req)
|
||||||
if err != nil || res.StatusCode != 200 {
|
if err != nil || res.StatusCode != 200 {
|
||||||
if res != nil {
|
if res != nil {
|
||||||
return nil, fmt.Errorf("Internal server error: %d trying to fetch remote history for %s", res.StatusCode, imgID)
|
return nil, utils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to fetch remote history for %s", res.StatusCode, imgID), res)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@ func (r *Registry) GetRemoteImageJSON(imgID, registry string, token []string) ([
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
if res.StatusCode != 200 {
|
if res.StatusCode != 200 {
|
||||||
return nil, -1, fmt.Errorf("HTTP code %d", res.StatusCode)
|
return nil, -1, utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
imageSize, err := strconv.Atoi(res.Header.Get("X-Docker-Size"))
|
imageSize, err := strconv.Atoi(res.Header.Get("X-Docker-Size"))
|
||||||
|
@ -289,12 +289,12 @@ func (r *Registry) GetRepositoryData(indexEp, remote string) (*RepositoryData, e
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
if res.StatusCode == 401 {
|
if res.StatusCode == 401 {
|
||||||
return nil, fmt.Errorf("Please login first (HTTP code %d)", res.StatusCode)
|
return nil, utils.NewHTTPRequestError(fmt.Sprintf("Please login first (HTTP code %d)", res.StatusCode), res)
|
||||||
}
|
}
|
||||||
// TODO: Right now we're ignoring checksums in the response body.
|
// TODO: Right now we're ignoring checksums in the response body.
|
||||||
// In the future, we need to use them to check image validity.
|
// In the future, we need to use them to check image validity.
|
||||||
if res.StatusCode != 200 {
|
if res.StatusCode != 200 {
|
||||||
return nil, fmt.Errorf("HTTP code: %d", res.StatusCode)
|
return nil, utils.NewHTTPRequestError(fmt.Sprintf("HTTP code: %d", res.StatusCode), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokens []string
|
var tokens []string
|
||||||
|
@ -391,7 +391,7 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis
|
||||||
if res.StatusCode != 200 {
|
if res.StatusCode != 200 {
|
||||||
errBody, err := ioutil.ReadAll(res.Body)
|
errBody, err := ioutil.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err)
|
return utils.NewHTTPRequestError(fmt.Sprint("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
|
||||||
}
|
}
|
||||||
var jsonBody map[string]string
|
var jsonBody map[string]string
|
||||||
if err := json.Unmarshal(errBody, &jsonBody); err != nil {
|
if err := json.Unmarshal(errBody, &jsonBody); err != nil {
|
||||||
|
@ -399,7 +399,7 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis
|
||||||
} else if jsonBody["error"] == "Image already exists" {
|
} else if jsonBody["error"] == "Image already exists" {
|
||||||
return ErrAlreadyExists
|
return ErrAlreadyExists
|
||||||
}
|
}
|
||||||
return fmt.Errorf("HTTP code %d while uploading metadata: %s", res.StatusCode, errBody)
|
return utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata: %s", res.StatusCode, errBody), res)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -427,9 +427,9 @@ func (r *Registry) PushImageLayerRegistry(imgID string, layer io.Reader, registr
|
||||||
if res.StatusCode != 200 {
|
if res.StatusCode != 200 {
|
||||||
errBody, err := ioutil.ReadAll(res.Body)
|
errBody, err := ioutil.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err)
|
return utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("Received HTTP code %d while uploading layer: %s", res.StatusCode, errBody)
|
return utils.NewHTTPRequestError(fmt.Sprintf("Received HTTP code %d while uploading layer: %s", res.StatusCode, errBody), res)
|
||||||
}
|
}
|
||||||
return tarsumLayer.Sum(jsonRaw), nil
|
return tarsumLayer.Sum(jsonRaw), nil
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,7 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token
|
||||||
}
|
}
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
if res.StatusCode != 200 && res.StatusCode != 201 {
|
if res.StatusCode != 200 && res.StatusCode != 201 {
|
||||||
return fmt.Errorf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote)
|
return utils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote), res)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -540,7 +540,7 @@ func (r *Registry) PushImageJSONIndex(indexEp, remote string, imgList []*ImgData
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("Error: Status %d trying to push repository %s: %s", res.StatusCode, remote, errBody)
|
return nil, utils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %s", res.StatusCode, remote, errBody), res)
|
||||||
}
|
}
|
||||||
if res.Header.Get("X-Docker-Token") != "" {
|
if res.Header.Get("X-Docker-Token") != "" {
|
||||||
tokens = res.Header["X-Docker-Token"]
|
tokens = res.Header["X-Docker-Token"]
|
||||||
|
@ -564,7 +564,7 @@ func (r *Registry) PushImageJSONIndex(indexEp, remote string, imgList []*ImgData
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("Error: Status %d trying to push checksums %s: %s", res.StatusCode, remote, errBody)
|
return nil, utils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %s", res.StatusCode, remote, errBody), res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,7 +586,7 @@ func (r *Registry) SearchRepositories(term string) (*SearchResults, error) {
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
if res.StatusCode != 200 {
|
if res.StatusCode != 200 {
|
||||||
return nil, fmt.Errorf("Unexepected status code %d", res.StatusCode)
|
return nil, utils.NewHTTPRequestError(fmt.Sprintf("Unexepected status code %d", res.StatusCode), res)
|
||||||
}
|
}
|
||||||
rawData, err := ioutil.ReadAll(res.Body)
|
rawData, err := ioutil.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HTTPRequestError struct {
|
||||||
|
Message string
|
||||||
|
StatusCode int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *HTTPRequestError) Error() string {
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHTTPRequestError(msg string, resp *http.Response) error {
|
||||||
|
return &HTTPRequestError{Message: msg, StatusCode: resp.StatusCode}
|
||||||
|
}
|
|
@ -607,12 +607,22 @@ func NewWriteFlusher(w io.Writer) *WriteFlusher {
|
||||||
return &WriteFlusher{w: w, flusher: flusher}
|
return &WriteFlusher{w: w, flusher: flusher}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type JSONError struct {
|
||||||
|
Code int `json:"code,omitempty"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type JSONMessage struct {
|
type JSONMessage struct {
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
Progress string `json:"progress,omitempty"`
|
Progress string `json:"progress,omitempty"`
|
||||||
Error string `json:"error,omitempty"`
|
ErrorMessage string `json:"error,omitempty"` //deprecated
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
Time int64 `json:"time,omitempty"`
|
Time int64 `json:"time,omitempty"`
|
||||||
|
Error *JSONError `json:"errorDetail,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *JSONError) Error() string {
|
||||||
|
return e.Message
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jm *JSONMessage) Display(out io.Writer) error {
|
func (jm *JSONMessage) Display(out io.Writer) error {
|
||||||
|
@ -621,8 +631,8 @@ func (jm *JSONMessage) Display(out io.Writer) error {
|
||||||
}
|
}
|
||||||
if jm.Progress != "" {
|
if jm.Progress != "" {
|
||||||
fmt.Fprintf(out, "%s %s\r", jm.Status, jm.Progress)
|
fmt.Fprintf(out, "%s %s\r", jm.Status, jm.Progress)
|
||||||
} else if jm.Error != "" {
|
} else if jm.Error != nil {
|
||||||
return fmt.Errorf(jm.Error)
|
return jm.Error
|
||||||
} else if jm.ID != "" {
|
} else if jm.ID != "" {
|
||||||
fmt.Fprintf(out, "%s: %s\n", jm.ID, jm.Status)
|
fmt.Fprintf(out, "%s: %s\n", jm.ID, jm.Status)
|
||||||
} else {
|
} else {
|
||||||
|
@ -656,7 +666,7 @@ func (sf *StreamFormatter) FormatStatus(format string, a ...interface{}) []byte
|
||||||
func (sf *StreamFormatter) FormatError(err error) []byte {
|
func (sf *StreamFormatter) FormatError(err error) []byte {
|
||||||
sf.used = true
|
sf.used = true
|
||||||
if sf.json {
|
if sf.json {
|
||||||
if b, err := json.Marshal(&JSONMessage{Error: err.Error()}); err == nil {
|
if b, err := json.Marshal(&JSONMessage{Error: &JSONError{Code: code, Message: err.Error()}, ErrorMessage: err.Error()}); err == nil {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
return []byte("{\"error\":\"format error\"}")
|
return []byte("{\"error\":\"format error\"}")
|
||||||
|
|
Loading…
Reference in New Issue