Merge pull request #2725 from ywk253100/170707_status_code

Return real status code returned by admiral APIs
This commit is contained in:
Wenkai Yin 2017-07-10 10:12:50 +08:00 committed by GitHub
commit 0b282039e9
17 changed files with 83 additions and 70 deletions

View File

@ -23,6 +23,7 @@ import (
"github.com/astaxie/beego/validation"
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/models"
http_error "github.com/vmware/harbor/src/common/utils/error"
"github.com/vmware/harbor/src/common/utils/log"
"github.com/vmware/harbor/src/ui/auth"
@ -80,6 +81,21 @@ func (b *BaseAPI) HandleInternalServerError(text string) {
b.RenderError(http.StatusInternalServerError, "")
}
// ParseAndHandleError : if the err is an instance of utils/error.Error,
// return the status code and the detail message contained in err, otherwise
// return 500
func (b *BaseAPI) ParseAndHandleError(text string, err error) {
if err == nil {
return
}
log.Errorf("%s: %v", text, err)
if e, ok := err.(*http_error.HTTPError); ok {
b.RenderError(e.StatusCode, e.Detail)
return
}
b.RenderError(http.StatusInternalServerError, "")
}
// Render returns nil as it won't render template
func (b *BaseAPI) Render() error {
return nil

View File

@ -26,6 +26,7 @@ import (
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/common/utils"
http_error "github.com/vmware/harbor/src/common/utils/error"
"github.com/vmware/harbor/src/common/utils/log"
)
@ -202,7 +203,10 @@ func send(client *http.Client, req *http.Request) (*AuthContext, error) {
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d %s", resp.StatusCode, string(data))
return nil, &http_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(data),
}
}
ctx := &AuthContext{}

View File

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

View File

@ -18,7 +18,7 @@ import (
)
func TestError(t *testing.T) {
err := &Error{
err := &HTTPError{
StatusCode: 404,
Detail: "not found",
}

View File

@ -78,7 +78,7 @@ func getToken(client *http.Client, credential Credential, realm, service string,
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, &registry_error.Error{
return nil, &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(data),
}

View File

@ -126,7 +126,7 @@ func (r *Registry) Catalog() ([]string, error) {
suffix = ""
}
} else {
return repos, &registry_error.Error{
return repos, &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}
@ -157,7 +157,7 @@ func (r *Registry) Ping() error {
return err
}
return &registry_error.Error{
return &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}

View File

@ -72,7 +72,7 @@ func NewRepositoryWithModifiers(name, endpoint string, insecure bool, modifiers
func parseError(err error) error {
if urlErr, ok := err.(*url.Error); ok {
if regErr, ok := urlErr.Err.(*registry_error.Error); ok {
if regErr, ok := urlErr.Err.(*registry_error.HTTPError); ok {
return regErr
}
}
@ -120,7 +120,7 @@ func (r *Repository) ListTag() ([]string, error) {
return tags, nil
}
return tags, &registry_error.Error{
return tags, &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}
@ -160,7 +160,7 @@ func (r *Repository) ManifestExist(reference string) (digest string, exist bool,
return
}
err = &registry_error.Error{
err = &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}
@ -197,7 +197,7 @@ func (r *Repository) PullManifest(reference string, acceptMediaTypes []string) (
return
}
err = &registry_error.Error{
err = &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}
@ -232,7 +232,7 @@ func (r *Repository) PushManifest(reference, mediaType string, payload []byte) (
return
}
err = &registry_error.Error{
err = &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}
@ -263,7 +263,7 @@ func (r *Repository) DeleteManifest(digest string) error {
return err
}
return &registry_error.Error{
return &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}
@ -277,7 +277,7 @@ func (r *Repository) DeleteTag(tag string) error {
}
if !exist {
return &registry_error.Error{
return &registry_error.HTTPError{
StatusCode: http.StatusNotFound,
}
}
@ -312,7 +312,7 @@ func (r *Repository) BlobExist(digest string) (bool, error) {
return false, err
}
return false, &registry_error.Error{
return false, &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}
@ -348,7 +348,7 @@ func (r *Repository) PullBlob(digest string) (size int64, data io.ReadCloser, er
return
}
err = &registry_error.Error{
err = &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}
@ -379,7 +379,7 @@ func (r *Repository) initiateBlobUpload(name string) (location, uploadUUID strin
return
}
err = &registry_error.Error{
err = &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}
@ -409,7 +409,7 @@ func (r *Repository) monolithicBlobUpload(location, digest string, size int64, d
return err
}
return &registry_error.Error{
return &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}
@ -447,7 +447,7 @@ func (r *Repository) DeleteBlob(digest string) error {
return err
}
return &registry_error.Error{
return &registry_error.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}

View File

@ -396,10 +396,10 @@ func TestListTag(t *testing.T) {
func TestParseError(t *testing.T) {
err := &url.Error{
Err: &registry_error.Error{},
Err: &registry_error.HTTPError{},
}
e := parseError(err)
if _, ok := e.(*registry_error.Error); !ok {
if _, ok := e.(*registry_error.HTTPError); !ok {
t.Errorf("error type does not match registry error")
}
}

View File

@ -67,8 +67,7 @@ func (pma *ProjectMemberAPI) Prepare() {
}
project, err := pma.ProjectMgr.Get(pid)
if err != nil {
pma.HandleInternalServerError(
fmt.Sprintf("failed to get project %d: %v", pid, err))
pma.ParseAndHandleError(fmt.Sprintf("failed to get project %d", pid), err)
return
}
if project == nil {

View File

@ -59,8 +59,7 @@ func (p *ProjectAPI) Prepare() {
project, err := p.ProjectMgr.Get(id)
if err != nil {
p.HandleInternalServerError(fmt.Sprintf("failed to get project %d: %v",
id, err))
p.ParseAndHandleError(fmt.Sprintf("failed to get project %d", id), err)
return
}
@ -107,8 +106,8 @@ func (p *ProjectAPI) Post() {
exist, err := p.ProjectMgr.Exist(pro.Name)
if err != nil {
p.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %s: %v",
pro.Name, err))
p.ParseAndHandleError(fmt.Sprintf("failed to check the existence of project %s",
pro.Name), err)
return
}
if exist {
@ -126,12 +125,12 @@ func (p *ProjectAPI) Post() {
AutomaticallyScanImagesOnPush: pro.AutomaticallyScanImagesOnPush,
})
if err != nil {
log.Errorf("Failed to add project, error: %v", err)
dup, _ := regexp.MatchString(dupProjectPattern, err.Error())
if dup {
log.Debugf("conflict %s", pro.Name)
p.RenderError(http.StatusConflict, "")
} else {
p.RenderError(http.StatusInternalServerError, "Failed to add project")
p.ParseAndHandleError("failed to add project", err)
}
return
}
@ -163,8 +162,7 @@ func (p *ProjectAPI) Head() {
project, err := p.ProjectMgr.Get(name)
if err != nil {
p.HandleInternalServerError(fmt.Sprintf("failed to get project %s: %v",
name, err))
p.ParseAndHandleError(fmt.Sprintf("failed to get project %s", name), err)
return
}
@ -223,8 +221,7 @@ func (p *ProjectAPI) Delete() {
}
if err = p.ProjectMgr.Delete(p.project.ProjectID); err != nil {
p.HandleInternalServerError(
fmt.Sprintf("failed to delete project %d: %v", p.project.ProjectID, err))
p.ParseAndHandleError(fmt.Sprintf("failed to delete project %d", p.project.ProjectID), err)
return
}
@ -299,13 +296,13 @@ func (p *ProjectAPI) List() {
total, err := p.ProjectMgr.GetTotal(query, base)
if err != nil {
p.HandleInternalServerError(fmt.Sprintf("failed to get total of projects: %v", err))
p.ParseAndHandleError("failed to get total of projects", err)
return
}
projects, err := p.ProjectMgr.GetAll(query, base)
if err != nil {
p.HandleInternalServerError(fmt.Sprintf("failed to get projects: %v", err))
p.ParseAndHandleError("failed to get projects", err)
return
}
@ -359,8 +356,8 @@ func (p *ProjectAPI) ToggleProjectPublic() {
&models.Project{
Public: req.Public,
}); err != nil {
p.HandleInternalServerError(fmt.Sprintf("failed to update project %d: %v",
p.project.ProjectID, err))
p.ParseAndHandleError(fmt.Sprintf("failed to update project %d",
p.project.ProjectID), err)
return
}
}

View File

@ -86,8 +86,8 @@ func (pa *RepPolicyAPI) List() {
for _, policy := range policies {
project, err := pa.ProjectMgr.Get(policy.ProjectID)
if err != nil {
pa.HandleInternalServerError(fmt.Sprintf(
"failed to get project %d: %v", policy.ProjectID, err))
pa.ParseAndHandleError(fmt.Sprintf(
"failed to get project %d", policy.ProjectID), err)
return
}
if project != nil {
@ -118,8 +118,8 @@ func (pa *RepPolicyAPI) Post() {
project, err := pa.ProjectMgr.Get(policy.ProjectID)
if err != nil {
log.Errorf("failed to get project %d: %v", policy.ProjectID, err)
pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
pa.ParseAndHandleError(fmt.Sprintf("failed to get project %d", policy.ProjectID), err)
return
}
if project == nil {

View File

@ -84,8 +84,8 @@ func (ra *RepositoryAPI) Get() {
exist, err := ra.ProjectMgr.Exist(projectID)
if err != nil {
ra.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %d: %v",
projectID, err))
ra.ParseAndHandleError(fmt.Sprintf("failed to check the existence of project %d",
projectID), err)
return
}
@ -169,8 +169,8 @@ func (ra *RepositoryAPI) Delete() {
projectName, _ := utils.ParseRepository(repoName)
project, err := ra.ProjectMgr.Get(projectName)
if err != nil {
ra.HandleInternalServerError(fmt.Sprintf("failed to get the project %s: %v",
projectName, err))
ra.ParseAndHandleError(fmt.Sprintf("failed to get the project %s",
projectName), err)
return
}
@ -200,7 +200,7 @@ func (ra *RepositoryAPI) Delete() {
if len(tag) == 0 {
tagList, err := rc.ListTag()
if err != nil {
if regErr, ok := err.(*registry_error.Error); ok {
if regErr, ok := err.(*registry_error.HTTPError); ok {
ra.CustomAbort(regErr.StatusCode, regErr.Detail)
}
@ -242,7 +242,7 @@ func (ra *RepositoryAPI) Delete() {
for _, t := range tags {
if err = rc.DeleteTag(t); err != nil {
if regErr, ok := err.(*registry_error.Error); ok {
if regErr, ok := err.(*registry_error.HTTPError); ok {
if regErr.StatusCode == http.StatusNotFound {
continue
}
@ -335,8 +335,8 @@ func (ra *RepositoryAPI) GetTags() {
projectName, _ := utils.ParseRepository(repoName)
exist, err := ra.ProjectMgr.Exist(projectName)
if err != nil {
ra.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %s: %v",
projectName, err))
ra.ParseAndHandleError(fmt.Sprintf("failed to check the existence of project %s",
projectName), err)
return
}
@ -475,8 +475,8 @@ func (ra *RepositoryAPI) GetManifests() {
projectName, _ := utils.ParseRepository(repoName)
exist, err := ra.ProjectMgr.Exist(projectName)
if err != nil {
ra.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %s: %v",
projectName, err))
ra.ParseAndHandleError(fmt.Sprintf("failed to check the existence of project %s",
projectName), err)
return
}
@ -503,7 +503,7 @@ func (ra *RepositoryAPI) GetManifests() {
manifest, err := getManifest(rc, tag, version)
if err != nil {
if regErr, ok := err.(*registry_error.Error); ok {
if regErr, ok := err.(*registry_error.HTTPError); ok {
ra.CustomAbort(regErr.StatusCode, regErr.Detail)
}
@ -577,7 +577,7 @@ func (ra *RepositoryAPI) GetTopRepos() {
projectIDs := []int64{}
projects, err := ra.ProjectMgr.GetPublic()
if err != nil {
ra.HandleInternalServerError(fmt.Sprintf("failed to get public projects: %v", err))
ra.ParseAndHandleError("failed to get public projects", err)
return
}
if ra.SecurityCtx.IsAuthenticated() {
@ -617,8 +617,8 @@ func (ra *RepositoryAPI) GetSignatures() {
projectName, _ := utils.ParseRepository(repoName)
exist, err := ra.ProjectMgr.Exist(projectName)
if err != nil {
ra.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %s: %v",
projectName, err))
ra.ParseAndHandleError(fmt.Sprintf("failed to check the existence of project %s",
projectName), err)
return
}
@ -658,8 +658,8 @@ func (ra *RepositoryAPI) ScanImage() {
projectName, _ := utils.ParseRepository(repoName)
exist, err := ra.ProjectMgr.Exist(projectName)
if err != nil {
ra.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %s: %v",
projectName, err))
ra.ParseAndHandleError(fmt.Sprintf("failed to check the existence of project %s",
projectName), err)
return
}
if !exist {
@ -776,7 +776,7 @@ func (ra *RepositoryAPI) checkExistence(repository, tag string) (bool, string, e
project, _ := utils.ParseRepository(repository)
exist, err := ra.ProjectMgr.Exist(project)
if err != nil {
return false, "", fmt.Errorf("failed to check the existence of project %s: %v", project, err)
return false, "", err
}
if !exist {
log.Errorf("project %s not found", project)

View File

@ -51,15 +51,13 @@ func (s *SearchAPI) Get() {
if isSysAdmin {
projects, err = s.ProjectMgr.GetAll(nil)
if err != nil {
s.HandleInternalServerError(fmt.Sprintf(
"failed to get projects: %v", err))
s.ParseAndHandleError("failed to get projects", err)
return
}
} else {
projects, err = s.ProjectMgr.GetPublic()
if err != nil {
s.HandleInternalServerError(fmt.Sprintf(
"failed to get projects: %v", err))
s.ParseAndHandleError("failed to get projects", err)
return
}
if isAuthenticated {

View File

@ -59,8 +59,7 @@ func (s *StatisticAPI) Get() {
statistic := map[string]int64{}
pubProjs, err := s.ProjectMgr.GetPublic()
if err != nil {
s.HandleInternalServerError(fmt.Sprintf(
"failed to get public projects: %v", err))
s.ParseAndHandleError("failed to get public projects", err)
return
}
@ -102,8 +101,8 @@ func (s *StatisticAPI) Get() {
},
})
if err != nil {
s.HandleInternalServerError(fmt.Sprintf(
"failed to get projects of user %s: %v", s.username, err))
s.ParseAndHandleError(fmt.Sprintf(
"failed to get projects of user %s", s.username), err)
return
}

View File

@ -81,7 +81,7 @@ func (t *TargetAPI) ping(endpoint, username, password string) {
}
if err = registry.Ping(); err != nil {
if regErr, ok := err.(*registry_error.Error); ok {
if regErr, ok := err.(*registry_error.HTTPError); ok {
t.CustomAbort(regErr.StatusCode, regErr.Detail)
}

View File

@ -440,7 +440,7 @@ func getReposByProject(name string, keyword ...string) ([]string, error) {
func repositoryExist(name string, client *registry.Repository) (bool, error) {
tags, err := client.ListTag()
if err != nil {
if regErr, ok := err.(*registry_error.Error); ok && regErr.StatusCode == http.StatusNotFound {
if regErr, ok := err.(*registry_error.HTTPError); ok && regErr.StatusCode == http.StatusNotFound {
return false, nil
}
return false, err

View File

@ -412,7 +412,7 @@ func (p *ProjectManager) send(method, path string, body io.Reader) ([]byte, erro
}
if resp.StatusCode != http.StatusOK {
return nil, &er.Error{
return nil, &er.HTTPError{
StatusCode: resp.StatusCode,
Detail: string(b),
}