From c237468ac98252b20d9c674b693461031b9e7eda Mon Sep 17 00:00:00 2001 From: Lizzy Thomson <71537606+lizzythomson@users.noreply.github.com> Date: Thu, 7 Jul 2022 20:01:08 -0600 Subject: [PATCH] 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 --- satellite/console/service.go | 26 +++++------ satellite/console/service_test.go | 75 +++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 13 deletions(-) diff --git a/satellite/console/service.go b/satellite/console/service.go index 78fe52cee..245bf5ca9 100644 --- a/satellite/console/service.go +++ b/satellite/console/service.go @@ -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. -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) 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) } - err = ValidateNameAndDescription(projectInfo.Name, projectInfo.Description) + err = ValidateNameAndDescription(updatedProject.Name, updatedProject.Description) if err != nil { 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) } project := isMember.project - project.Name = projectInfo.Name - project.Description = projectInfo.Description + project.Name = updatedProject.Name + project.Description = updatedProject.Description if user.PaidTier { 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 { 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") } - 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") } - 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") } @@ -1594,7 +1594,7 @@ func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, projec if err != nil { 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") } @@ -1602,14 +1602,14 @@ func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, projec if err != nil { 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") } project.StorageLimit = new(memory.Size) - *project.StorageLimit = projectInfo.StorageLimit + *project.StorageLimit = updatedProject.StorageLimit project.BandwidthLimit = new(memory.Size) - *project.BandwidthLimit = projectInfo.BandwidthLimit + *project.BandwidthLimit = updatedProject.BandwidthLimit } 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{ Status: http.StatusBadRequest, 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{ Status: http.StatusBadRequest, Err: Error.New("specified bandwidth limit exceeds allowed maximum for current tier"), diff --git a/satellite/console/service_test.go b/satellite/console/service_test.go index 622bc0c27..e45a834ef 100644 --- a/satellite/console/service_test.go +++ b/satellite/console/service_test.go @@ -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) { testplanet.Run(t, testplanet.Config{ SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,