Merge pull request #3101 from ywk253100/170822_replica

Convert 500 error returned by Admiral to duplicate project error when creating duplicate project
This commit is contained in:
Daniel Jiang 2017-08-22 15:59:19 +08:00 committed by GitHub
commit f41d2ff436
6 changed files with 77 additions and 4 deletions

View File

@ -15,9 +15,13 @@
package error
import (
"errors"
"fmt"
)
// ErrDupProject is the error returned when creating a duplicate project
var ErrDupProject = errors.New("duplicate project")
// HTTPError : if response is returned but the status code is not 200, an Error instance will be returned
type HTTPError struct {
StatusCode int

View File

@ -23,6 +23,7 @@ import (
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/common/utils"
errutil "github.com/vmware/harbor/src/common/utils/error"
"github.com/vmware/harbor/src/common/utils/log"
"github.com/vmware/harbor/src/ui/config"
@ -44,7 +45,6 @@ type ProjectAPI struct {
const projectNameMaxLen int = 30
const projectNameMinLen int = 2
const restrictedNameChars = `[a-z0-9]+(?:[._-][a-z0-9]+)*`
const dupProjectPattern = `Duplicate entry '\w+' for key 'name'`
// Prepare validates the URL and the user
func (p *ProjectAPI) Prepare() {
@ -130,8 +130,7 @@ func (p *ProjectAPI) Post() {
AutomaticallyScanImagesOnPush: pro.AutomaticallyScanImagesOnPush,
})
if err != nil {
dup, _ := regexp.MatchString(dupProjectPattern, err.Error())
if dup {
if err == errutil.ErrDupProject {
log.Debugf("conflict %s", pro.Name)
p.RenderError(http.StatusConflict, "")
} else {

View File

@ -16,12 +16,17 @@ package db
import (
"fmt"
"regexp"
"time"
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/models"
errutil "github.com/vmware/harbor/src/common/utils/error"
"github.com/vmware/harbor/src/common/utils/log"
)
const dupProjectPattern = `Duplicate entry '\w+' for key 'name'`
// ProjectManager implements pm.PM interface based on database
type ProjectManager struct{}
@ -105,7 +110,21 @@ func (p *ProjectManager) Create(project *models.Project) (int64, error) {
UpdateTime: t,
}
return dao.AddProject(*pro)
id, err := dao.AddProject(*pro)
if err != nil {
dup, e := regexp.MatchString(dupProjectPattern, err.Error())
if e != nil {
log.Errorf("failed to match duplicate project pattern: %v", e)
}
if dup {
err = errutil.ErrDupProject
}
return 0, err
}
return id, nil
}
// Delete ...

View File

@ -22,6 +22,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/models"
errutil "github.com/vmware/harbor/src/common/utils/error"
"github.com/vmware/harbor/src/common/utils/log"
)
@ -166,6 +167,19 @@ func TestCreateAndDelete(t *testing.T) {
})
assert.Nil(t, err)
assert.Nil(t, pm.Delete(id))
// duplicate project name
id, err = pm.Create(&models.Project{
Name: "test",
OwnerName: "admin",
})
assert.Nil(t, err)
defer pm.Delete(id)
_, err = pm.Create(&models.Project{
Name: "test",
OwnerName: "admin",
})
assert.Equal(t, errutil.ErrDupProject, err)
}
func TestUpdate(t *testing.T) {

View File

@ -22,6 +22,7 @@ import (
"io"
"io/ioutil"
"net/http"
"regexp"
"strconv"
"strings"
@ -31,6 +32,8 @@ import (
"github.com/vmware/harbor/src/common/utils/log"
)
const dupProjectPattern = `Project name '\w+' is already used`
// ProjectManager implements projectmanager.ProjecdtManager interface
// base on project management service
type ProjectManager struct {
@ -366,6 +369,33 @@ func (p *ProjectManager) Create(pro *models.Project) (int64, error) {
b, err := p.send(http.MethodPost, "/projects", bytes.NewBuffer(data))
if err != nil {
// when creating a project with a duplicate name in Admiral, a 500 error
// with a specific message will be returned for now.
// Maybe a 409 error will be returned if Admiral team finds the way to
// return a specific code in Xenon.
// The following codes convert both those two errors to DupProjectErr
httpErr, ok := err.(*er.HTTPError)
if !ok {
return 0, err
}
if httpErr.StatusCode == http.StatusConflict {
return 0, er.ErrDupProject
}
if httpErr.StatusCode != http.StatusInternalServerError {
return 0, err
}
match, e := regexp.MatchString(dupProjectPattern, httpErr.Detail)
if e != nil {
log.Errorf("failed to match duplicate project mattern: %v", e)
}
if match {
err = er.ErrDupProject
}
return 0, err
}

View File

@ -22,6 +22,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vmware/harbor/src/common/models"
errutil "github.com/vmware/harbor/src/common/utils/error"
)
var (
@ -344,6 +345,12 @@ func TestCreate(t *testing.T) {
assert.True(t, project.PreventVulnerableImagesFromRunning)
assert.Equal(t, "medium", project.PreventVulnerableImagesFromRunningSeverity)
assert.True(t, project.AutomaticallyScanImagesOnPush)
// duplicate project name
_, err = pm.Create(&models.Project{
Name: name,
})
assert.Equal(t, errutil.ErrDupProject, err)
}
func TestDelete(t *testing.T) {