Update creating project API to support proxy cache project

Update creating project API to support proxy cache project

Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
Wenkai Yin 2020-06-10 17:14:12 +08:00
parent d5cce98d56
commit a79bb127b3
7 changed files with 62 additions and 12 deletions

View File

@ -3766,6 +3766,10 @@ definitions:
type: integer
format: int64
description: The storage quota of the project.
registry_id:
type: integer
format: int64
description: The ID of referenced registry when creating the proxy cache project
Project:
type: object
properties:
@ -3780,6 +3784,10 @@ definitions:
name:
type: string
description: The name of the project.
registry_id:
type: integer
format: int64
description: The ID of referenced registry when the project is a proxy cache project.
creation_time:
type: string
description: The creation time of the project.

View File

@ -0,0 +1 @@
ALTER TABLE project ADD COLUMN IF NOT EXISTS registry_id int;

View File

@ -27,11 +27,11 @@ import (
func AddProject(project models.Project) (int64, error) {
o := GetOrmer()
sql := "insert into project (owner_id, name, creation_time, update_time, deleted) values (?, ?, ?, ?, ?) RETURNING project_id"
sql := "insert into project (owner_id, name, registry_id, creation_time, update_time, deleted) values (?, ?, ?, ?, ?, ?) RETURNING project_id"
var projectID int64
now := time.Now()
err := o.Raw(sql, project.OwnerID, project.Name, now, now, project.Deleted).QueryRow(&projectID)
err := o.Raw(sql, project.OwnerID, project.Name, project.RegistryID, now, now, project.Deleted).QueryRow(&projectID)
if err != nil {
return 0, err
}
@ -78,7 +78,7 @@ func addProjectMember(member models.Member) (int, error) {
func GetProjectByID(id int64) (*models.Project, error) {
o := GetOrmer()
sql := `select p.project_id, p.name, u.username as owner_name, p.owner_id, p.creation_time, p.update_time
sql := `select p.project_id, p.name, p.registry_id, u.username as owner_name, p.owner_id, p.creation_time, p.update_time
from project p left join harbor_user u on p.owner_id = u.user_id where p.deleted = false and p.project_id = ?`
queryParam := make([]interface{}, 1)
queryParam = append(queryParam, id)
@ -142,7 +142,7 @@ func GetTotalOfProjects(query *models.ProjectQueryParam) (int64, error) {
// GetProjects returns a project list according to the query conditions
func GetProjects(query *models.ProjectQueryParam) ([]*models.Project, error) {
sqlStr, queryParam := projectQueryConditions(query)
sqlStr = `select distinct p.project_id, p.name, p.owner_id,
sqlStr = `select distinct p.project_id, p.name, p.registry_id, p.owner_id,
p.creation_time, p.update_time ` + sqlStr + ` order by p.name`
sqlStr, queryParam = CreatePagination(query, sqlStr, queryParam)
@ -157,12 +157,12 @@ func GetProjects(query *models.ProjectQueryParam) ([]*models.Project, error) {
// and the user is in the group which is a group member of this project.
func GetGroupProjects(groupIDs []int, query *models.ProjectQueryParam) ([]*models.Project, error) {
sql, params := projectQueryConditions(query)
sql = `select distinct p.project_id, p.name, p.owner_id,
sql = `select distinct p.project_id, p.name, p.registry_id, p.owner_id,
p.creation_time, p.update_time ` + sql
groupIDCondition := JoinNumberConditions(groupIDs)
if len(groupIDs) > 0 {
sql = fmt.Sprintf(
`%s union select distinct p.project_id, p.name, p.owner_id, p.creation_time, p.update_time
`%s union select distinct p.project_id, p.name, p.registry_id, p.owner_id, p.creation_time, p.update_time
from project p
left join project_member pm on p.project_id = pm.project_id
left join user_group ug on ug.id = pm.entity_id and pm.entity_type = 'g'
@ -237,6 +237,11 @@ func projectQueryConditions(query *models.ProjectQueryParam) (string, []interfac
params = append(params, "%"+Escape(query.Name)+"%")
}
if query.RegistryID > 0 {
sql += ` and p.registry_id = ?`
params = append(params, query.RegistryID)
}
if query.Member != nil && len(query.Member.Name) != 0 {
sql += ` and u2.username=?`
params = append(params, query.Member.Name)

View File

@ -45,6 +45,7 @@ type Project struct {
ChartCount uint64 `orm:"-" json:"chart_count"`
Metadata map[string]string `orm:"-" json:"metadata"`
CVEWhitelist CVEWhitelist `orm:"-" json:"cve_whitelist"`
RegistryID int64 `orm:"column(registry_id)" json:"registry_id"`
}
// GetMetadata ...
@ -136,9 +137,10 @@ func isTrue(value string) bool {
// List projects which user1 is member of: query := &QueryParam{Member:&Member{Name:"user1"}}
// List projects which user1 is the project admin : query := &QueryParam{Member:&Member{Name:"user1",Role:1}}
type ProjectQueryParam struct {
Name string // the name of project
Owner string // the username of project owner
Public *bool // the project is public or not, can be ture, false and nil
Name string // the name of project
Owner string // the username of project owner
Public *bool // the project is public or not, can be ture, false and nil
RegistryID int64
Member *MemberQuery // the member of project
Pagination *Pagination // pagination information
ProjectIDs []int64 // project ID list
@ -178,6 +180,7 @@ type ProjectRequest struct {
CVEWhitelist CVEWhitelist `json:"cve_whitelist"`
StorageLimit *int64 `json:"storage_limit,omitempty"`
RegistryID int64 `json:"registry_id"`
}
// ProjectQueryResult ...

View File

@ -17,6 +17,7 @@ package api
import (
"context"
"fmt"
"github.com/goharbor/harbor/src/replication"
"net/http"
"regexp"
"strconv"
@ -126,6 +127,24 @@ func (p *ProjectAPI) Post() {
return
}
// trying to create a proxy cache project
if pro.RegistryID > 0 {
// only system admin can create the proxy cache project
if !p.SecurityCtx.IsSysAdmin() {
p.SendForbiddenError(errors.New("Only system admin can create proxy cache project"))
return
}
registry, err := replication.RegistryMgr.Get(pro.RegistryID)
if err != nil {
p.SendInternalServerError(fmt.Errorf("failed to get the registry %d: %v", pro.RegistryID, err))
return
}
if registry == nil {
p.SendNotFoundError(fmt.Errorf("registry %d not found", pro.RegistryID))
return
}
}
var hardLimits types.ResourceList
if config.QuotaPerProjectEnable() {
setting, err := config.QuotaSetting()
@ -187,9 +206,10 @@ func (p *ProjectAPI) Post() {
owner = user.Username
}
projectID, err := p.ProjectMgr.Create(&models.Project{
Name: pro.Name,
OwnerName: owner,
Metadata: pro.Metadata,
Name: pro.Name,
OwnerName: owner,
Metadata: pro.Metadata,
RegistryID: pro.RegistryID,
})
if err != nil {
if err == errutil.ErrDupProject {

View File

@ -7,6 +7,7 @@ import (
"strconv"
common_http "github.com/goharbor/harbor/src/common/http"
common_models "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/utils"
"github.com/goharbor/harbor/src/core/api/models"
"github.com/goharbor/harbor/src/lib/log"
@ -375,6 +376,17 @@ func (t *RegistryAPI) Delete() {
return
}
// check whether the registry is referenced by any proxy cache projects
result, err := t.ProjectMgr.List(&common_models.ProjectQueryParam{RegistryID: id})
if err != nil {
t.SendInternalServerError(fmt.Errorf("failed to list projects: %v", err))
return
}
if result != nil && result.Total > 0 {
t.SendPreconditionFailedError(fmt.Errorf("Can't delete registry %d, %d proxy cache projects referennce it", id, result.Total))
return
}
if err := t.manager.Remove(id); err != nil {
msg := fmt.Sprintf("Delete registry %d error: %v", id, err)
log.Error(msg)

View File

@ -83,6 +83,7 @@ func (d *driver) Create(project *models.Project) (int64, error) {
pro := &models.Project{
Name: project.Name,
OwnerID: project.OwnerID,
RegistryID: project.RegistryID,
CreationTime: t,
UpdateTime: t,
}