mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-22 23:51:27 +01:00
Project name validation to prevent system artifact reserved project names (#17029)
Include system artifact size in system storage space calculation. Signed-off-by: prahaladdarkin <prahaladd@vmware.com>
This commit is contained in:
parent
aab320591f
commit
7024442f25
@ -19,6 +19,7 @@ var (
|
||||
)
|
||||
|
||||
const repositoryFormat = "sys_harbor/%s/%s"
|
||||
const systemArtifactProjectName = "sys_h@rb0r"
|
||||
|
||||
// Manager provides a low-level interface for harbor services
|
||||
// to create registry artifacts containing arbitrary data but which
|
||||
@ -64,6 +65,10 @@ type Manager interface {
|
||||
// artifact records selected by the Selector registered for each vendor type.
|
||||
// Returns the total number of records deleted, the reclaimed size and any error (if encountered)
|
||||
Cleanup(ctx context.Context) (int64, int64, error)
|
||||
|
||||
// GetSystemArtifactProjectNames returns a list of project names that are reserved
|
||||
// to be used by the system artifact manager for creation of system artifacts.
|
||||
GetSystemArtifactProjectNames() []string
|
||||
}
|
||||
|
||||
type systemArtifactManager struct {
|
||||
@ -167,6 +172,10 @@ func (mgr *systemArtifactManager) GetCleanupCriteria(vendor string, artifactType
|
||||
return DefaultSelector
|
||||
}
|
||||
|
||||
func (mgr *systemArtifactManager) GetSystemArtifactProjectNames() []string {
|
||||
return []string{systemArtifactProjectName}
|
||||
}
|
||||
|
||||
func (mgr *systemArtifactManager) Cleanup(ctx context.Context) (int64, int64, error) {
|
||||
logger.Info("Starting system artifact cleanup")
|
||||
// clean up artifact records having customized cleanup criteria first
|
||||
|
@ -478,6 +478,12 @@ func (suite *ManagerTestSuite) TestCleanupErrorForVendor() {
|
||||
suite.NoErrorf(err, "Expected no error, but was %v", err)
|
||||
}
|
||||
|
||||
func (suite *ManagerTestSuite) TestGetSystemArtifactProjectNames() {
|
||||
reservedProjectNames := suite.mgr.GetSystemArtifactProjectNames()
|
||||
suite.Equalf(1, len(reservedProjectNames), "Expected: %d, Actual: %d", 1, len(reservedProjectNames))
|
||||
suite.Equalf(systemArtifactProjectName, reservedProjectNames[0], "Expected: %s, Actual: %s", systemArtifactProjectName, reservedProjectNames[0])
|
||||
}
|
||||
|
||||
func (suite *ManagerTestSuite) List(ctx context.Context) ([]*model.SystemArtifact, error) {
|
||||
return make([]*model.SystemArtifact, 0), nil
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ package handler
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/controller/blob"
|
||||
"github.com/goharbor/harbor/src/pkg/systemartifact"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/goharbor/harbor/src/common/security/local"
|
||||
@ -29,17 +30,19 @@ import (
|
||||
|
||||
func newStatisticAPI() *statisticAPI {
|
||||
return &statisticAPI{
|
||||
proCtl: project.Ctl,
|
||||
repoCtl: repository.Ctl,
|
||||
blobCtl: blob.Ctl,
|
||||
proCtl: project.Ctl,
|
||||
repoCtl: repository.Ctl,
|
||||
blobCtl: blob.Ctl,
|
||||
systemArtifactMgr: systemartifact.Mgr,
|
||||
}
|
||||
}
|
||||
|
||||
type statisticAPI struct {
|
||||
BaseAPI
|
||||
proCtl project.Controller
|
||||
repoCtl repository.Controller
|
||||
blobCtl blob.Controller
|
||||
proCtl project.Controller
|
||||
repoCtl repository.Controller
|
||||
blobCtl blob.Controller
|
||||
systemArtifactMgr systemartifact.Manager
|
||||
}
|
||||
|
||||
func (s *statisticAPI) GetStatistic(ctx context.Context, params operation.GetStatisticParams) middleware.Responder {
|
||||
@ -96,7 +99,13 @@ func (s *statisticAPI) GetStatistic(ctx context.Context, params operation.GetSta
|
||||
if err != nil {
|
||||
return s.SendError(ctx, err)
|
||||
}
|
||||
statistic.TotalStorageConsumption = sum
|
||||
|
||||
sysArtifactStorageSize, err := s.systemArtifactMgr.GetStorageSize(ctx)
|
||||
|
||||
if err != nil {
|
||||
return s.SendError(ctx, err)
|
||||
}
|
||||
statistic.TotalStorageConsumption = sum + sysArtifactStorageSize
|
||||
} else {
|
||||
var privProjectIDs []interface{}
|
||||
if sc, ok := securityCtx.(*local.SecurityContext); ok && sc.IsAuthenticated() {
|
||||
|
63
src/server/v2.0/handler/statistic_test.go
Normal file
63
src/server/v2.0/handler/statistic_test.go
Normal file
@ -0,0 +1,63 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/pkg/project/models"
|
||||
models2 "github.com/goharbor/harbor/src/server/v2.0/models"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/restapi"
|
||||
blobtesting "github.com/goharbor/harbor/src/testing/controller/blob"
|
||||
projecttesting "github.com/goharbor/harbor/src/testing/controller/project"
|
||||
repositorytesting "github.com/goharbor/harbor/src/testing/controller/repository"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
systemartifacttesting "github.com/goharbor/harbor/src/testing/pkg/systemartifact"
|
||||
htesting "github.com/goharbor/harbor/src/testing/server/v2.0/handler"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type StatisticsTestSuite struct {
|
||||
htesting.Suite
|
||||
projectCtl *projecttesting.Controller
|
||||
repoCtl *repositorytesting.Controller
|
||||
blobCtl *blobtesting.Controller
|
||||
sysArtifactMgr *systemartifacttesting.Manager
|
||||
}
|
||||
|
||||
func (suite *StatisticsTestSuite) SetupSuite() {
|
||||
suite.projectCtl = &projecttesting.Controller{}
|
||||
suite.repoCtl = &repositorytesting.Controller{}
|
||||
suite.blobCtl = &blobtesting.Controller{}
|
||||
suite.sysArtifactMgr = &systemartifacttesting.Manager{}
|
||||
|
||||
suite.Config = &restapi.Config{StatisticAPI: &statisticAPI{
|
||||
proCtl: suite.projectCtl,
|
||||
repoCtl: suite.repoCtl,
|
||||
blobCtl: suite.blobCtl,
|
||||
systemArtifactMgr: suite.sysArtifactMgr,
|
||||
}}
|
||||
suite.Suite.SetupSuite()
|
||||
}
|
||||
|
||||
func (suite *StatisticsTestSuite) TestGetStatistic() {
|
||||
projects := make([]*models.Project, 0)
|
||||
suite.projectCtl.On("List", mock.Anything, mock.Anything, mock.Anything).Return(projects, nil)
|
||||
suite.projectCtl.On("Count", mock.Anything, mock.Anything).Return(int64(10), nil)
|
||||
suite.repoCtl.On("Count", mock.Anything, mock.Anything).Return(int64(20), nil)
|
||||
suite.blobCtl.On("CalculateTotalSize", mock.Anything, true).Return(int64(1000), nil)
|
||||
suite.sysArtifactMgr.On("GetStorageSize", mock.Anything).Return(int64(1000), nil)
|
||||
|
||||
suite.Security.On("IsAuthenticated").Return(true)
|
||||
suite.Security.On("Can", mock.Anything, mock.Anything, mock.Anything).Return(true)
|
||||
suite.Security.On("IsSysAdmin").Return(true)
|
||||
|
||||
var statistics models2.Statistic
|
||||
res, err := suite.GetJSON("/statistics", &statistics)
|
||||
suite.NoError(err)
|
||||
suite.Equal(200, res.StatusCode)
|
||||
suite.Equal(int64(2000), statistics.TotalStorageConsumption)
|
||||
suite.Equal(int64(10), statistics.PrivateProjectCount)
|
||||
suite.Equal(int64(20), statistics.PrivateRepoCount)
|
||||
suite.Equal(int64(20), statistics.TotalRepoCount)
|
||||
}
|
||||
func TestStatisticsSuite(t *testing.T) {
|
||||
suite.Run(t, &StatisticsTestSuite{})
|
||||
}
|
@ -139,6 +139,22 @@ func (_m *Manager) GetStorageSize(ctx context.Context) (int64, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetSystemArtifactProjectNames provides a mock function with given fields:
|
||||
func (_m *Manager) GetSystemArtifactProjectNames() []string {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 []string
|
||||
if rf, ok := ret.Get(0).(func() []string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Read provides a mock function with given fields: ctx, vendor, repository, digest
|
||||
func (_m *Manager) Read(ctx context.Context, vendor string, repository string, digest string) (io.ReadCloser, error) {
|
||||
ret := _m.Called(ctx, vendor, repository, digest)
|
||||
|
Loading…
Reference in New Issue
Block a user