CRUD of target API

This commit is contained in:
Wenkai Yin 2016-05-24 14:59:36 +08:00
parent 7449b3604c
commit de72efaba8
8 changed files with 155 additions and 195 deletions

View File

@ -29,7 +29,7 @@ import (
svc_utils "github.com/vmware/harbor/service/utils" svc_utils "github.com/vmware/harbor/service/utils"
"github.com/vmware/harbor/utils/log" "github.com/vmware/harbor/utils/log"
"github.com/vmware/harbor/utils/registry" "github.com/vmware/harbor/utils/registry"
"github.com/vmware/harbor/utils/registry/errors" registry_error "github.com/vmware/harbor/utils/registry/error"
) )
// RepositoryAPI handles request to /api/repositories /api/repositories/tags /api/repositories/manifests, the parm has to be put // RepositoryAPI handles request to /api/repositories /api/repositories/tags /api/repositories/manifests, the parm has to be put
@ -116,14 +116,12 @@ func (ra *RepositoryAPI) Delete() {
if len(tag) == 0 { if len(tag) == 0 {
tagList, err := rc.ListTag() tagList, err := rc.ListTag()
if err != nil { if err != nil {
e, ok := errors.ParseError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { ra.CustomAbort(regErr.StatusCode, regErr.Detail)
log.Info(e)
ra.CustomAbort(e.StatusCode, e.Message)
} else {
log.Error(err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
} }
log.Errorf("error occurred while listing tags of %s: %v", repoName, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
} }
tags = append(tags, tagList...) tags = append(tags, tagList...)
} else { } else {
@ -132,13 +130,12 @@ func (ra *RepositoryAPI) Delete() {
for _, t := range tags { for _, t := range tags {
if err := rc.DeleteTag(t); err != nil { if err := rc.DeleteTag(t); err != nil {
e, ok := errors.ParseError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { ra.CustomAbort(regErr.StatusCode, regErr.Detail)
ra.CustomAbort(e.StatusCode, e.Message)
} else {
log.Error(err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
} }
log.Errorf("error occurred while deleting tags of %s: %v", repoName, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
} }
log.Infof("delete tag: %s %s", repoName, t) log.Infof("delete tag: %s %s", repoName, t)
} }
@ -174,13 +171,12 @@ func (ra *RepositoryAPI) GetTags() {
ts, err := rc.ListTag() ts, err := rc.ListTag()
if err != nil { if err != nil {
e, ok := errors.ParseError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { ra.CustomAbort(regErr.StatusCode, regErr.Detail)
ra.CustomAbort(e.StatusCode, e.Message)
} else {
log.Error(err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
} }
log.Errorf("error occurred while listing tags of %s: %v", repoName, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
} }
tags = append(tags, ts...) tags = append(tags, ts...)
@ -209,13 +205,12 @@ func (ra *RepositoryAPI) GetManifests() {
mediaTypes := []string{schema1.MediaTypeManifest} mediaTypes := []string{schema1.MediaTypeManifest}
_, _, payload, err := rc.PullManifest(tag, mediaTypes) _, _, payload, err := rc.PullManifest(tag, mediaTypes)
if err != nil { if err != nil {
e, ok := errors.ParseError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { ra.CustomAbort(regErr.StatusCode, regErr.Detail)
ra.CustomAbort(e.StatusCode, e.Message)
} else {
log.Error(err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
} }
log.Errorf("error occurred while getting manifest of %s:%s: %v", repoName, tag, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
} }
mani := models.Manifest{} mani := models.Manifest{}
err = json.Unmarshal(payload, &mani) err = json.Unmarshal(payload, &mani)

View File

@ -18,6 +18,7 @@ package api
import ( import (
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"net"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
@ -27,6 +28,7 @@ import (
"github.com/vmware/harbor/utils/log" "github.com/vmware/harbor/utils/log"
registry_util "github.com/vmware/harbor/utils/registry" registry_util "github.com/vmware/harbor/utils/registry"
"github.com/vmware/harbor/utils/registry/auth" "github.com/vmware/harbor/utils/registry/auth"
registry_error "github.com/vmware/harbor/utils/registry/error"
) )
// TargetAPI handles request to /api/targets/ping /api/targets/{} // TargetAPI handles request to /api/targets/ping /api/targets/{}
@ -64,9 +66,24 @@ func (t *TargetAPI) Ping() {
log.Errorf("failed to get target %d: %v", id, err) log.Errorf("failed to get target %d: %v", id, err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
} }
if target == nil {
t.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound))
}
endpoint = target.URL endpoint = target.URL
username = target.Username username = target.Username
password = target.Password password = target.Password
if len(password) != 0 {
b, err := base64.StdEncoding.DecodeString(password)
if err != nil {
log.Errorf("failed to decode password: %v", err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
password = string(b)
}
} else { } else {
endpoint = t.GetString("endpoint") endpoint = t.GetString("endpoint")
if len(endpoint) == 0 { if len(endpoint) == 0 {
@ -74,58 +91,44 @@ func (t *TargetAPI) Ping() {
} }
username = t.GetString("username") username = t.GetString("username")
pwd := t.GetString("password") password = t.GetString("password")
b, err := base64.StdEncoding.DecodeString(pwd)
if err != nil {
log.Errorf("failed to decode password: %v", err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
password = string(b)
} }
credential := auth.NewBasicAuthCredential(username, password) credential := auth.NewBasicAuthCredential(username, password)
registry, err := registry_util.NewRegistryWithCredential(endpoint, credential) registry, err := registry_util.NewRegistryWithCredential(endpoint, credential)
if err != nil { if err != nil {
log.Errorf("failed to create registry client: %v", err) // timeout, dns resolve error, connection refused, etc.
if urlErr, ok := err.(*url.Error); ok {
if netErr, ok := urlErr.Err.(net.Error); ok {
t.CustomAbort(http.StatusBadRequest, netErr.Error())
} else {
t.CustomAbort(http.StatusBadRequest, urlErr.Error())
}
}
log.Errorf("failed to create registry client: %#v", err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
} }
if err = registry.Ping(); err != nil { if err = registry.Ping(); err != nil {
log.Errorf("failed to ping registry %s: %v", registry.Endpoint.String(), err)
// timeout, dns resolve error, connection refused, etc. // timeout, dns resolve error, connection refused, etc.
if urlErr, ok := err.(*url.Error); ok { if urlErr, ok := err.(*url.Error); ok {
t.CustomAbort(http.StatusBadRequest, urlErr.Error()) if netErr, ok := urlErr.Err.(net.Error); ok {
t.CustomAbort(http.StatusBadRequest, netErr.Error())
} else {
t.CustomAbort(http.StatusBadRequest, urlErr.Error())
}
} }
if regErr, ok := err.(*registry_util.Error); ok { if regErr, ok := err.(*registry_error.Error); ok {
t.CustomAbort(regErr.StatusCode, regErr.Detail) t.CustomAbort(regErr.StatusCode, regErr.Detail)
} }
log.Errorf("failed to ping registry %s: %v", registry.Endpoint.String(), err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
} }
} }
// Head ...
func (t *TargetAPI) Head() {
id := t.getIDFromURL()
if id == 0 {
t.CustomAbort(http.StatusBadRequest, http.StatusText(http.StatusBadRequest))
}
target, err := dao.GetRepTarget(id)
if err != nil {
log.Errorf("failed to get target %d: %v", id, err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
// not exist
if target == nil {
t.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound))
}
}
// Get ... // Get ...
func (t *TargetAPI) Get() { func (t *TargetAPI) Get() {
id := t.getIDFromURL() id := t.getIDFromURL()
@ -222,6 +225,28 @@ func (t *TargetAPI) Put() {
} }
} }
func (t *TargetAPI) Delete() {
id := t.getIDFromURL()
if id == 0 {
t.CustomAbort(http.StatusBadRequest, http.StatusText(http.StatusBadRequest))
}
target, err := dao.GetRepTarget(id)
if err != nil {
log.Errorf("failed to get target %d: %v", id, err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
if target == nil {
t.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound))
}
if err = dao.DeleteRepTarget(id); err != nil {
log.Errorf("failed to delete target %d: %v", id, err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
}
func (t *TargetAPI) getIDFromURL() int64 { func (t *TargetAPI) getIDFromURL() int64 {
idStr := t.Ctx.Input.Param(":id") idStr := t.Ctx.Input.Param(":id")
if len(idStr) == 0 { if len(idStr) == 0 {

View File

@ -62,7 +62,7 @@ func initRouters() {
beego.Router("/api/repositories/tags", &api.RepositoryAPI{}, "get:GetTags") beego.Router("/api/repositories/tags", &api.RepositoryAPI{}, "get:GetTags")
beego.Router("/api/repositories/manifests", &api.RepositoryAPI{}, "get:GetManifests") beego.Router("/api/repositories/manifests", &api.RepositoryAPI{}, "get:GetManifests")
beego.Router("/api/targets/?:id", &api.TargetAPI{}) beego.Router("/api/targets/?:id", &api.TargetAPI{})
beego.Router("/api/targets/ping", &api.TargetAPI{}, "get:Ping") beego.Router("/api/target_ping", &api.TargetAPI{}, "get:Ping")
//external service that hosted on harbor process: //external service that hosted on harbor process:
beego.Router("/service/notifications", &service.NotificationHandler{}) beego.Router("/service/notifications", &service.NotificationHandler{})

View File

@ -27,7 +27,7 @@ import (
token_util "github.com/vmware/harbor/service/token" token_util "github.com/vmware/harbor/service/token"
"github.com/vmware/harbor/utils/log" "github.com/vmware/harbor/utils/log"
registry_errors "github.com/vmware/harbor/utils/registry/errors" registry_error "github.com/vmware/harbor/utils/registry/error"
) )
type scope struct { type scope struct {
@ -75,7 +75,9 @@ func (t *tokenHandler) AuthorizeRequest(req *http.Request, params map[string]str
hasFrom = true hasFrom = true
} }
scopes = append(scopes, t.scope) if t.scope != nil {
scopes = append(scopes, t.scope)
}
expired := true expired := true
@ -143,11 +145,14 @@ func NewStandardTokenHandler(credential Credential, scopeType, scopeName string,
credential: credential, credential: credential,
} }
handler.scope = &scope{ if len(scopeType) != 0 || len(scopeName) != 0 {
Type: scopeType, handler.scope = &scope{
Name: scopeName, Type: scopeType,
Actions: scopeActions, Name: scopeName,
Actions: scopeActions,
}
} }
handler.tg = handler.generateToken handler.tg = handler.generateToken
return handler return handler
@ -182,10 +187,9 @@ func (s *standardTokenHandler) generateToken(realm, service string, scopes []str
return return
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
err = registry_errors.Error{ err = &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
return return
} }

View File

@ -13,17 +13,19 @@
limitations under the License. limitations under the License.
*/ */
package registry package error
import ( import (
"fmt" "fmt"
) )
// Error : if response is returned but the status code is not 200, an Error instance will be returned
type Error struct { type Error struct {
StatusCode int StatusCode int
Detail string Detail string
} }
// Error returns the details as string
func (e *Error) Error() string { func (e *Error) Error() string {
return fmt.Sprintf("%d %s", e.StatusCode, e.Detail) return fmt.Sprintf("%d %s", e.StatusCode, e.Detail)
} }

View File

@ -1,39 +0,0 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package errors
import (
"fmt"
)
// Error : if response's status code is not 200 or does not meet requirement,
// an Error instance will be returned
type Error struct {
StatusCode int
StatusText string
Message string
}
// Error ...
func (e Error) Error() string {
return fmt.Sprintf("%d %s %s", e.StatusCode, e.StatusText, e.Message)
}
// ParseError parses err, if err is type Error, convert it to Error
func ParseError(err error) (Error, bool) {
e, ok := err.(Error)
return e, ok
}

View File

@ -25,7 +25,7 @@ import (
"github.com/vmware/harbor/utils/log" "github.com/vmware/harbor/utils/log"
"github.com/vmware/harbor/utils/registry/auth" "github.com/vmware/harbor/utils/registry/auth"
"github.com/vmware/harbor/utils/registry/errors" registry_error "github.com/vmware/harbor/utils/registry/error"
) )
const ( const (
@ -121,10 +121,10 @@ func (r *Registry) Catalog() ([]string, error) {
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { return repos, regErr
return repos, e
} }
return repos, err return repos, err
} }
@ -149,10 +149,9 @@ func (r *Registry) Catalog() ([]string, error) {
return repos, nil return repos, nil
} }
return repos, errors.Error{ return repos, &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
} }
@ -165,10 +164,16 @@ func (r *Registry) Ping() error {
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if urlErr, ok := err.(*url.Error); ok {
if ok { if regErr, ok := urlErr.Err.(*registry_error.Error); ok {
return e return &registry_error.Error{
StatusCode: regErr.StatusCode,
Detail: regErr.Detail,
}
}
return urlErr.Err
} }
return err return err
} }
@ -183,10 +188,9 @@ func (r *Registry) Ping() error {
return err return err
} }
return errors.Error{ return &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
} }

View File

@ -30,7 +30,7 @@ import (
"github.com/docker/distribution/manifest/schema2" "github.com/docker/distribution/manifest/schema2"
"github.com/vmware/harbor/utils/log" "github.com/vmware/harbor/utils/log"
"github.com/vmware/harbor/utils/registry/auth" "github.com/vmware/harbor/utils/registry/auth"
"github.com/vmware/harbor/utils/registry/errors" registry_error "github.com/vmware/harbor/utils/registry/error"
) )
// Repository holds information of a repository entity // Repository holds information of a repository entity
@ -112,17 +112,6 @@ func NewRepositoryWithUsername(name, endpoint, username string) (*Repository, er
return repository, nil return repository, nil
} }
// try to convert err to errors.Error if it is
func isUnauthorizedError(err error) (bool, error) {
if strings.Contains(err.Error(), http.StatusText(http.StatusUnauthorized)) {
return true, errors.Error{
StatusCode: http.StatusUnauthorized,
StatusText: http.StatusText(http.StatusUnauthorized),
}
}
return false, err
}
// ListTag ... // ListTag ...
func (r *Repository) ListTag() ([]string, error) { func (r *Repository) ListTag() ([]string, error) {
tags := []string{} tags := []string{}
@ -133,10 +122,10 @@ func (r *Repository) ListTag() ([]string, error) {
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { return tags, regErr
return tags, e
} }
return tags, err return tags, err
} }
@ -160,10 +149,9 @@ func (r *Repository) ListTag() ([]string, error) {
return tags, nil return tags, nil
} }
return tags, errors.Error{ return tags, &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
} }
@ -180,9 +168,8 @@ func (r *Repository) ManifestExist(reference string) (digest string, exist bool,
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { err = regErr
err = e
return return
} }
return return
@ -205,10 +192,9 @@ func (r *Repository) ManifestExist(reference string) (digest string, exist bool,
return return
} }
err = errors.Error{ err = &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
return return
} }
@ -226,9 +212,8 @@ func (r *Repository) PullManifest(reference string, acceptMediaTypes []string) (
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { err = regErr
err = e
return return
} }
return return
@ -247,10 +232,9 @@ func (r *Repository) PullManifest(reference string, acceptMediaTypes []string) (
return return
} }
err = errors.Error{ err = &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
return return
@ -267,9 +251,8 @@ func (r *Repository) PushManifest(reference, mediaType string, payload []byte) (
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { err = regErr
err = e
return return
} }
return return
@ -287,10 +270,9 @@ func (r *Repository) PushManifest(reference, mediaType string, payload []byte) (
return return
} }
err = errors.Error{ err = &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
return return
@ -305,9 +287,8 @@ func (r *Repository) DeleteManifest(digest string) error {
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { return regErr
return e
} }
return err return err
} }
@ -323,10 +304,9 @@ func (r *Repository) DeleteManifest(digest string) error {
return err return err
} }
return errors.Error{ return &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
} }
@ -338,9 +318,8 @@ func (r *Repository) DeleteTag(tag string) error {
} }
if !exist { if !exist {
return errors.Error{ return &registry_error.Error{
StatusCode: http.StatusNotFound, StatusCode: http.StatusNotFound,
StatusText: http.StatusText(http.StatusNotFound),
} }
} }
@ -356,9 +335,8 @@ func (r *Repository) BlobExist(digest string) (bool, error) {
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { return false, regErr
return false, e
} }
return false, err return false, err
} }
@ -378,10 +356,9 @@ func (r *Repository) BlobExist(digest string) (bool, error) {
return false, err return false, err
} }
return false, errors.Error{ return false, &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
} }
@ -394,9 +371,8 @@ func (r *Repository) PullBlob(digest string) (size int64, data io.ReadCloser, er
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { err = regErr
err = e
return return
} }
return return
@ -418,10 +394,9 @@ func (r *Repository) PullBlob(digest string) (size int64, data io.ReadCloser, er
return return
} }
err = errors.Error{ err = &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
return return
@ -433,9 +408,8 @@ func (r *Repository) initiateBlobUpload(name string) (location, uploadUUID strin
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { err = regErr
err = e
return return
} }
return return
@ -454,10 +428,9 @@ func (r *Repository) initiateBlobUpload(name string) (location, uploadUUID strin
return return
} }
err = errors.Error{ err = &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
return return
@ -471,9 +444,8 @@ func (r *Repository) monolithicBlobUpload(location, digest string, size int64, d
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { return regErr
return e
} }
return err return err
} }
@ -489,10 +461,9 @@ func (r *Repository) monolithicBlobUpload(location, digest string, size int64, d
return err return err
} }
return errors.Error{ return &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
} }
@ -515,9 +486,8 @@ func (r *Repository) DeleteBlob(digest string) error {
resp, err := r.client.Do(req) resp, err := r.client.Do(req)
if err != nil { if err != nil {
ok, e := isUnauthorizedError(err) if regErr, ok := err.(*registry_error.Error); ok {
if ok { return regErr
return e
} }
return err return err
} }
@ -533,10 +503,9 @@ func (r *Repository) DeleteBlob(digest string) error {
return err return err
} }
return errors.Error{ return &registry_error.Error{
StatusCode: resp.StatusCode, StatusCode: resp.StatusCode,
StatusText: resp.Status, Detail: string(b),
Message: string(b),
} }
} }