Merge remote-tracking branch 'upstream/job-service' into job-service

This commit is contained in:
Tan Jiang 2016-05-25 15:26:24 +08:00
commit b80e727b7f
11 changed files with 471 additions and 135 deletions

View File

@ -30,7 +30,7 @@ import (
svc_utils "github.com/vmware/harbor/service/utils"
"github.com/vmware/harbor/utils/log"
"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
@ -121,14 +121,12 @@ func (ra *RepositoryAPI) Delete() {
if len(tag) == 0 {
tagList, err := rc.ListTag()
if err != nil {
e, ok := errors.ParseError(err)
if ok {
log.Info(e)
ra.CustomAbort(e.StatusCode, e.Message)
} else {
log.Error(err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
if regErr, ok := err.(*registry_error.Error); ok {
ra.CustomAbort(regErr.StatusCode, regErr.Detail)
}
log.Errorf("error occurred while listing tags of %s: %v", repoName, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
}
tags = append(tags, tagList...)
} else {
@ -137,13 +135,12 @@ func (ra *RepositoryAPI) Delete() {
for _, t := range tags {
if err := rc.DeleteTag(t); err != nil {
e, ok := errors.ParseError(err)
if ok {
ra.CustomAbort(e.StatusCode, e.Message)
} else {
log.Error(err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
if regErr, ok := err.(*registry_error.Error); ok {
ra.CustomAbort(regErr.StatusCode, regErr.Detail)
}
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)
}
@ -179,13 +176,12 @@ func (ra *RepositoryAPI) GetTags() {
ts, err := rc.ListTag()
if err != nil {
e, ok := errors.ParseError(err)
if ok {
ra.CustomAbort(e.StatusCode, e.Message)
} else {
log.Error(err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
if regErr, ok := err.(*registry_error.Error); ok {
ra.CustomAbort(regErr.StatusCode, regErr.Detail)
}
log.Errorf("error occurred while listing tags of %s: %v", repoName, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
}
tags = append(tags, ts...)
@ -214,13 +210,12 @@ func (ra *RepositoryAPI) GetManifests() {
mediaTypes := []string{schema1.MediaTypeManifest}
_, _, payload, err := rc.PullManifest(tag, mediaTypes)
if err != nil {
e, ok := errors.ParseError(err)
if ok {
ra.CustomAbort(e.StatusCode, e.Message)
} else {
log.Error(err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
if regErr, ok := err.(*registry_error.Error); ok {
ra.CustomAbort(regErr.StatusCode, regErr.Detail)
}
log.Errorf("error occurred while getting manifest of %s:%s: %v", repoName, tag, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
}
mani := models.Manifest{}
err = json.Unmarshal(payload, &mani)

262
api/target.go Normal file
View File

@ -0,0 +1,262 @@
/*
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 api
import (
"encoding/base64"
"fmt"
"net"
"net/http"
"net/url"
"strconv"
"github.com/vmware/harbor/dao"
"github.com/vmware/harbor/models"
"github.com/vmware/harbor/utils/log"
registry_util "github.com/vmware/harbor/utils/registry"
"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/{}
type TargetAPI struct {
BaseAPI
}
// Prepare validates the user
func (t *TargetAPI) Prepare() {
userID := t.ValidateUser()
isSysAdmin, err := dao.IsAdminRole(userID)
if err != nil {
log.Errorf("error occurred in IsAdminRole: %v", err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
if !isSysAdmin {
t.CustomAbort(http.StatusForbidden, http.StatusText(http.StatusForbidden))
}
}
// Ping validates whether the target is reachable and whether the credential is valid
func (t *TargetAPI) Ping() {
var endpoint, username, password string
idStr := t.GetString("id")
if len(idStr) != 0 {
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
t.CustomAbort(http.StatusBadRequest, fmt.Sprintf("id %s is invalid", idStr))
}
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))
}
endpoint = target.URL
username = target.Username
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 {
endpoint = t.GetString("endpoint")
if len(endpoint) == 0 {
t.CustomAbort(http.StatusBadRequest, "id or endpoint is needed")
}
username = t.GetString("username")
password = t.GetString("password")
}
credential := auth.NewBasicAuthCredential(username, password)
registry, err := registry_util.NewRegistryWithCredential(endpoint, credential)
if err != nil {
// 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))
}
if err = registry.Ping(); err != nil {
// 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())
}
}
if regErr, ok := err.(*registry_error.Error); ok {
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))
}
}
// Get ...
func (t *TargetAPI) Get() {
id := t.getIDFromURL()
// list targets
if id == 0 {
targets, err := dao.GetAllRepTargets()
if err != nil {
log.Errorf("failed to get all targets: %v", err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
for _, target := range targets {
if len(target.Password) != 0 {
b, err := base64.StdEncoding.DecodeString(target.Password)
if err != nil {
log.Errorf("failed to decode password: %v", err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
target.Password = string(b)
}
}
t.Data["json"] = targets
t.ServeJSON()
return
}
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 len(target.Password) != 0 {
b, err := base64.StdEncoding.DecodeString(target.Password)
if err != nil {
log.Errorf("failed to decode password: %v", err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
target.Password = string(b)
}
t.Data["json"] = target
t.ServeJSON()
}
// Post
func (t *TargetAPI) Post() {
target := &models.RepTarget{}
t.DecodeJSONReq(target)
if len(target.Name) == 0 || len(target.URL) == 0 {
t.CustomAbort(http.StatusBadRequest, "name or URL is nil")
}
if len(target.Password) != 0 {
target.Password = base64.StdEncoding.EncodeToString([]byte(target.Password))
}
id, err := dao.AddRepTarget(*target)
if err != nil {
log.Errorf("failed to add target: %v", err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
t.Redirect(http.StatusCreated, strconv.FormatInt(id, 10))
}
// Put ...
func (t *TargetAPI) Put() {
id := t.getIDFromURL()
if id == 0 {
t.CustomAbort(http.StatusBadRequest, http.StatusText(http.StatusBadRequest))
}
target := &models.RepTarget{}
t.DecodeJSONReq(target)
if target.ID != id {
t.CustomAbort(http.StatusBadRequest, "IDs mismatch")
}
if len(target.Password) != 0 {
target.Password = base64.StdEncoding.EncodeToString([]byte(target.Password))
}
if err := dao.UpdateRepTarget(*target); err != nil {
log.Errorf("failed to update target %d: %v", id, err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
}
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 {
idStr := t.Ctx.Input.Param(":id")
if len(idStr) == 0 {
return 0
}
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
t.CustomAbort(http.StatusBadRequest, "invalid ID in request URL")
}
return id
}

View File

@ -26,6 +26,20 @@ func DeleteRepTarget(id int64) error {
return err
}
func UpdateRepTarget(target models.RepTarget) error {
o := orm.NewOrm()
_, err := o.Update(&target)
return err
}
func GetAllRepTargets() ([]*models.RepTarget, error) {
o := orm.NewOrm()
qs := o.QueryTable(&models.RepTarget{})
var targets []*models.RepTarget
_, err := qs.All(&targets)
return targets, err
}
func AddRepPolicy(policy models.RepPolicy) (int64, error) {
o := orm.NewOrm()
sqlTpl := `insert into replication_policy (name, project_id, target_id, enabled, description, cron_str, start_time, creation_time, update_time ) values (?, ?, ?, ?, ?, ?, %s, NOW(), NOW())`

View File

@ -201,9 +201,14 @@ func (c *Checker) projectExist() (exist, canWrite bool, err error) {
return
}
exist = true
// TODO handle canWrite when new API is ready
canWrite = true
for _, project := range projects {
if project.Name == c.project {
exist = true
canWrite = (project.Role == models.PROJECTADMIN ||
project.Role == models.DEVELOPER)
break
}
}
return
}

View File

@ -24,6 +24,7 @@ import (
"github.com/vmware/harbor/models"
"github.com/vmware/harbor/service/cache"
"github.com/vmware/harbor/utils/log"
"github.com/vmware/harbor/utils/registry"
"github.com/astaxie/beego"
)
@ -54,7 +55,8 @@ func (n *NotificationHandler) Post() {
log.Errorf("Failed to match the media type against pattern, error: %v", err)
matched = false
}
if matched && strings.HasPrefix(e.Request.UserAgent, "docker") {
if matched && (strings.HasPrefix(e.Request.UserAgent, "docker") ||
strings.ToLower(strings.TrimSpace(e.Request.UserAgent)) == strings.ToLower(registry.UserAgent)) {
username = e.Actor.Name
action = e.Action
repo = e.Target.Repository

View File

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

View File

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

View File

@ -13,27 +13,19 @@
limitations under the License.
*/
package errors
package error
import (
"fmt"
)
// Error : if response's status code is not 200 or does not meet requirement,
// an Error instance will be returned
// Error : if response is returned but the status code is not 200, an Error instance will be returned
type Error struct {
StatusCode int
StatusText string
Message string
Detail 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
// Error returns the details as string
func (e *Error) Error() string {
return fmt.Sprintf("%d %s", e.StatusCode, e.Detail)
}

View File

@ -25,7 +25,11 @@ import (
"github.com/vmware/harbor/utils/log"
"github.com/vmware/harbor/utils/registry/auth"
"github.com/vmware/harbor/utils/registry/errors"
registry_error "github.com/vmware/harbor/utils/registry/error"
)
const (
UserAgent string = "registry-client"
)
// Registry holds information of a registry entity
@ -78,6 +82,34 @@ func NewRegistryWithUsername(endpoint, username string) (*Registry, error) {
return registry, nil
}
func NewRegistryWithCredential(endpoint string, credential auth.Credential) (*Registry, error) {
endpoint = strings.TrimSpace(endpoint)
endpoint = strings.TrimRight(endpoint, "/")
if !strings.HasPrefix(endpoint, "http://") &&
!strings.HasPrefix(endpoint, "https://") {
endpoint = "http://" + endpoint
}
u, err := url.Parse(endpoint)
if err != nil {
return nil, err
}
client, err := newClient(endpoint, "", credential, "", "", "")
if err != nil {
return nil, err
}
registry := &Registry{
Endpoint: u,
client: client,
}
log.Debugf("initialized a registry client with credential: %s", endpoint)
return registry, nil
}
// Catalog ...
func (r *Registry) Catalog() ([]string, error) {
repos := []string{}
@ -89,10 +121,10 @@ func (r *Registry) Catalog() ([]string, error) {
resp, err := r.client.Do(req)
if err != nil {
ok, e := isUnauthorizedError(err)
if ok {
return repos, e
if regErr, ok := err.(*registry_error.Error); ok {
return repos, regErr
}
return repos, err
}
@ -117,10 +149,48 @@ func (r *Registry) Catalog() ([]string, error) {
return repos, nil
}
return repos, errors.Error{
return repos, &registry_error.Error{
StatusCode: resp.StatusCode,
StatusText: resp.Status,
Message: string(b),
Detail: string(b),
}
}
// Ping ...
func (r *Registry) Ping() error {
req, err := http.NewRequest("GET", buildPingURL(r.Endpoint.String()), nil)
if err != nil {
return err
}
resp, err := r.client.Do(req)
if err != nil {
if urlErr, ok := err.(*url.Error); ok {
if regErr, ok := urlErr.Err.(*registry_error.Error); ok {
return &registry_error.Error{
StatusCode: regErr.StatusCode,
Detail: regErr.Detail,
}
}
return urlErr.Err
}
return err
}
if resp.StatusCode == http.StatusOK {
return nil
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
return &registry_error.Error{
StatusCode: resp.StatusCode,
Detail: string(b),
}
}
@ -149,8 +219,9 @@ func newClient(endpoint, username string, credential auth.Credential,
challenges := auth.ParseChallengeFromResponse(resp)
authorizer := auth.NewRequestAuthorizer(handlers, challenges)
headerModifier := NewHeaderModifier(map[string]string{http.CanonicalHeaderKey("User-Agent"): UserAgent})
transport := NewTransport(http.DefaultTransport, []RequestModifier{authorizer})
transport := NewTransport(http.DefaultTransport, []RequestModifier{authorizer, headerModifier})
return &http.Client{
Transport: transport,
}, nil

View File

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

View File

@ -26,6 +26,26 @@ type RequestModifier interface {
ModifyRequest(*http.Request) error
}
// HeaderModifier adds headers to request
type HeaderModifier struct {
headers map[string]string
}
// NewHeaderModifier ...
func NewHeaderModifier(headers map[string]string) *HeaderModifier {
return &HeaderModifier{
headers: headers,
}
}
// ModifyRequest adds headers to the request
func (h *HeaderModifier) ModifyRequest(req *http.Request) error {
for key, value := range h.headers {
req.Header.Add(key, value)
}
return nil
}
// Transport holds information about base transport and modifiers
type Transport struct {
transport http.RoundTripper