satellite/console: allow user to update project when limits are above paid defaults
When a user's bandwidth/storage limits are manually set to exceed the paid tier defaults, attempting to update their project via the satellite UI (e.g. to change the name/description) would result in an error. This change modifies the limit checks for updating a project to remove this issue. https://github.com/storj/storj/issues/4892 Change-Id: I48853a3289b0ac51587f268a18c1b25743123fcf
This commit is contained in:
parent
d72f9525d4
commit
c237468ac9
@ -1550,7 +1550,7 @@ func (s *Service) GenDeleteProject(ctx context.Context, projectID uuid.UUID) (ht
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateProject is a method for updating project name and description by id.
|
// UpdateProject is a method for updating project name and description by id.
|
||||||
func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, projectInfo ProjectInfo) (p *Project, err error) {
|
func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, updatedProject ProjectInfo) (p *Project, err error) {
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
user, err := s.getUserAndAuditLog(ctx, "update project name and description", zap.String("projectID", projectID.String()))
|
user, err := s.getUserAndAuditLog(ctx, "update project name and description", zap.String("projectID", projectID.String()))
|
||||||
@ -1558,7 +1558,7 @@ func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, projec
|
|||||||
return nil, Error.Wrap(err)
|
return nil, Error.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ValidateNameAndDescription(projectInfo.Name, projectInfo.Description)
|
err = ValidateNameAndDescription(updatedProject.Name, updatedProject.Description)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Error.Wrap(err)
|
return nil, Error.Wrap(err)
|
||||||
}
|
}
|
||||||
@ -1568,8 +1568,8 @@ func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, projec
|
|||||||
return nil, Error.Wrap(err)
|
return nil, Error.Wrap(err)
|
||||||
}
|
}
|
||||||
project := isMember.project
|
project := isMember.project
|
||||||
project.Name = projectInfo.Name
|
project.Name = updatedProject.Name
|
||||||
project.Description = projectInfo.Description
|
project.Description = updatedProject.Description
|
||||||
|
|
||||||
if user.PaidTier {
|
if user.PaidTier {
|
||||||
if project.BandwidthLimit != nil && *project.BandwidthLimit == 0 {
|
if project.BandwidthLimit != nil && *project.BandwidthLimit == 0 {
|
||||||
@ -1578,15 +1578,15 @@ func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, projec
|
|||||||
if project.StorageLimit != nil && *project.StorageLimit == 0 {
|
if project.StorageLimit != nil && *project.StorageLimit == 0 {
|
||||||
return nil, Error.New("current storage limit for project is set to 0 (updating disabled)")
|
return nil, Error.New("current storage limit for project is set to 0 (updating disabled)")
|
||||||
}
|
}
|
||||||
if projectInfo.StorageLimit <= 0 || projectInfo.BandwidthLimit <= 0 {
|
if updatedProject.StorageLimit <= 0 || updatedProject.BandwidthLimit <= 0 {
|
||||||
return nil, Error.New("project limits must be greater than 0")
|
return nil, Error.New("project limits must be greater than 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
if projectInfo.StorageLimit > s.config.UsageLimits.Storage.Paid {
|
if updatedProject.StorageLimit > s.config.UsageLimits.Storage.Paid && updatedProject.StorageLimit > *project.StorageLimit {
|
||||||
return nil, Error.New("specified storage limit exceeds allowed maximum for current tier")
|
return nil, Error.New("specified storage limit exceeds allowed maximum for current tier")
|
||||||
}
|
}
|
||||||
|
|
||||||
if projectInfo.BandwidthLimit > s.config.UsageLimits.Bandwidth.Paid {
|
if updatedProject.BandwidthLimit > s.config.UsageLimits.Bandwidth.Paid && updatedProject.BandwidthLimit > *project.BandwidthLimit {
|
||||||
return nil, Error.New("specified bandwidth limit exceeds allowed maximum for current tier")
|
return nil, Error.New("specified bandwidth limit exceeds allowed maximum for current tier")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1594,7 +1594,7 @@ func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, projec
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Error.Wrap(err)
|
return nil, Error.Wrap(err)
|
||||||
}
|
}
|
||||||
if projectInfo.StorageLimit.Int64() < storageUsed {
|
if updatedProject.StorageLimit.Int64() < storageUsed {
|
||||||
return nil, Error.New("cannot set storage limit below current usage")
|
return nil, Error.New("cannot set storage limit below current usage")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1602,14 +1602,14 @@ func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, projec
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Error.Wrap(err)
|
return nil, Error.Wrap(err)
|
||||||
}
|
}
|
||||||
if projectInfo.BandwidthLimit.Int64() < bandwidthUsed {
|
if updatedProject.BandwidthLimit.Int64() < bandwidthUsed {
|
||||||
return nil, Error.New("cannot set bandwidth limit below current usage")
|
return nil, Error.New("cannot set bandwidth limit below current usage")
|
||||||
}
|
}
|
||||||
|
|
||||||
project.StorageLimit = new(memory.Size)
|
project.StorageLimit = new(memory.Size)
|
||||||
*project.StorageLimit = projectInfo.StorageLimit
|
*project.StorageLimit = updatedProject.StorageLimit
|
||||||
project.BandwidthLimit = new(memory.Size)
|
project.BandwidthLimit = new(memory.Size)
|
||||||
*project.BandwidthLimit = projectInfo.BandwidthLimit
|
*project.BandwidthLimit = updatedProject.BandwidthLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.store.Projects().Update(ctx, project)
|
err = s.store.Projects().Update(ctx, project)
|
||||||
@ -1672,14 +1672,14 @@ func (s *Service) GenUpdateProject(ctx context.Context, projectID uuid.UUID, pro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if projectInfo.StorageLimit > s.config.UsageLimits.Storage.Paid {
|
if projectInfo.StorageLimit > s.config.UsageLimits.Storage.Paid && projectInfo.StorageLimit > *project.StorageLimit {
|
||||||
return nil, api.HTTPError{
|
return nil, api.HTTPError{
|
||||||
Status: http.StatusBadRequest,
|
Status: http.StatusBadRequest,
|
||||||
Err: Error.New("specified storage limit exceeds allowed maximum for current tier"),
|
Err: Error.New("specified storage limit exceeds allowed maximum for current tier"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if projectInfo.BandwidthLimit > s.config.UsageLimits.Bandwidth.Paid {
|
if projectInfo.BandwidthLimit > s.config.UsageLimits.Bandwidth.Paid && projectInfo.BandwidthLimit > *project.BandwidthLimit {
|
||||||
return nil, api.HTTPError{
|
return nil, api.HTTPError{
|
||||||
Status: http.StatusBadRequest,
|
Status: http.StatusBadRequest,
|
||||||
Err: Error.New("specified bandwidth limit exceeds allowed maximum for current tier"),
|
Err: Error.New("specified bandwidth limit exceeds allowed maximum for current tier"),
|
||||||
|
@ -382,6 +382,81 @@ func TestPaidTier(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestUpdateProjectExceedsLimits ensures that a project with limits manually set above the defaults can be updated.
|
||||||
|
func TestUpdateProjectExceedsLimits(t *testing.T) {
|
||||||
|
usageConfig := console.UsageLimitsConfig{
|
||||||
|
Storage: console.StorageLimitConfig{
|
||||||
|
Free: memory.GB,
|
||||||
|
Paid: memory.TB,
|
||||||
|
},
|
||||||
|
Bandwidth: console.BandwidthLimitConfig{
|
||||||
|
Free: 2 * memory.GB,
|
||||||
|
Paid: 2 * memory.TB,
|
||||||
|
},
|
||||||
|
Segment: console.SegmentLimitConfig{
|
||||||
|
Free: 10,
|
||||||
|
Paid: 50,
|
||||||
|
},
|
||||||
|
Project: console.ProjectLimitConfig{
|
||||||
|
Free: 1,
|
||||||
|
Paid: 3,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testplanet.Run(t, testplanet.Config{
|
||||||
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1,
|
||||||
|
Reconfigure: testplanet.Reconfigure{
|
||||||
|
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
|
||||||
|
config.Console.UsageLimits = usageConfig
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
||||||
|
sat := planet.Satellites[0]
|
||||||
|
service := sat.API.Console.Service
|
||||||
|
projectID := planet.Uplinks[0].Projects[0].ID
|
||||||
|
|
||||||
|
updatedName := "newName"
|
||||||
|
updatedDescription := "newDescription"
|
||||||
|
updatedStorageLimit := memory.Size(100) + memory.TB
|
||||||
|
updatedBandwidthLimit := memory.Size(100) + memory.TB
|
||||||
|
|
||||||
|
proj, err := sat.API.DB.Console().Projects().Get(ctx, projectID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
userCtx1, err := sat.UserContext(ctx, proj.OwnerID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// project should have free tier usage limits
|
||||||
|
require.Equal(t, usageConfig.Storage.Free, *proj.StorageLimit)
|
||||||
|
require.Equal(t, usageConfig.Bandwidth.Free, *proj.BandwidthLimit)
|
||||||
|
require.Equal(t, usageConfig.Segment.Free, *proj.SegmentLimit)
|
||||||
|
|
||||||
|
// update project name should succeed
|
||||||
|
_, err = service.UpdateProject(userCtx1, projectID, console.ProjectInfo{
|
||||||
|
Name: updatedName,
|
||||||
|
Description: updatedDescription,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// manually set project limits above defaults
|
||||||
|
proj1, err := sat.API.DB.Console().Projects().Get(ctx, projectID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
proj1.StorageLimit = new(memory.Size)
|
||||||
|
*proj1.StorageLimit = updatedStorageLimit
|
||||||
|
proj1.BandwidthLimit = new(memory.Size)
|
||||||
|
*proj1.BandwidthLimit = updatedBandwidthLimit
|
||||||
|
err = sat.DB.Console().Projects().Update(ctx, proj1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// try to update project name should succeed
|
||||||
|
_, err = service.UpdateProject(userCtx1, projectID, console.ProjectInfo{
|
||||||
|
Name: "updatedName",
|
||||||
|
Description: "updatedDescription",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestMFA(t *testing.T) {
|
func TestMFA(t *testing.T) {
|
||||||
testplanet.Run(t, testplanet.Config{
|
testplanet.Run(t, testplanet.Config{
|
||||||
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
||||||
|
Loading…
Reference in New Issue
Block a user