Skip to content

Commit

Permalink
satellite/console: change default project and usage limits
Browse files Browse the repository at this point in the history
This is one step for implementing the free tier:
* Change the default project limit from 10 to 3
* Move storage and bandwidth project usage limits from the metainfo
package to the console package (otherwise there is a cyclical
dependency, and metainfo doesn't use these values anyway)
* Change the default storage usage limit per project from 500gb to 50gb
* Change the default bandwidth usage limit per project from 500gb to 50gb
* Migrate the database so that old users and projects continue to have
the old defaults (10 projects/500gb usage)

Change-Id: Ice9ee6a738bc6410da18c336c672d3fcd0cab1b9
  • Loading branch information
mobyvb committed Mar 24, 2021
1 parent 034eb2c commit 27bcb46
Show file tree
Hide file tree
Showing 15 changed files with 662 additions and 66 deletions.
8 changes: 5 additions & 3 deletions private/testplanet/satellite.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,7 @@ func (planet *Planet) newSatellite(ctx context.Context, prefix string, index int
CacheExpiration: 10 * time.Second,
},
ProjectLimits: metainfo.ProjectLimitConfig{
MaxBuckets: 10,
DefaultMaxUsage: 25 * memory.GB,
DefaultMaxBandwidth: 25 * memory.GB,
MaxBuckets: 10,
},
PieceDeletion: piecedeletion.Config{
MaxConcurrency: 100,
Expand Down Expand Up @@ -592,6 +590,10 @@ func (planet *Planet) newSatellite(ctx context.Context, prefix string, index int
Config: console.Config{
PasswordCost: console.TestPasswordCost,
DefaultProjectLimit: 5,
UsageLimits: console.UsageLimitsConfig{
DefaultStorageLimit: 25 * memory.GB,
DefaultBandwidthLimit: 25 * memory.GB,
},
},
RateLimit: web.IPRateLimiterConfig{
Duration: 5 * time.Minute,
Expand Down
4 changes: 2 additions & 2 deletions satellite/accounting/projectlimitcache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ func TestProjectLimitCache(t *testing.T) {
projectUsageSvc := saPeer.Accounting.ProjectUsage
accountingDB := saPeer.DB.ProjectAccounting()
projectLimitCache := saPeer.ProjectLimits.Cache
defaultUsageLimit := saPeer.Config.Metainfo.ProjectLimits.DefaultMaxUsage.Int64()
defaultBandwidthLimit := saPeer.Config.Metainfo.ProjectLimits.DefaultMaxBandwidth.Int64()
defaultUsageLimit := saPeer.Config.Console.UsageLimits.DefaultStorageLimit.Int64()
defaultBandwidthLimit := saPeer.Config.Console.UsageLimits.DefaultBandwidthLimit.Int64()
dbDefaultLimits := accounting.ProjectLimits{Usage: &defaultUsageLimit, Bandwidth: &defaultBandwidthLimit}

testProject, err := saPeer.DB.Console().Projects().Insert(ctx, &console.Project{Name: "test", OwnerID: testrand.UUID()})
Expand Down
4 changes: 2 additions & 2 deletions satellite/accounting/projectusage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ func TestProjectUsageStorage(t *testing.T) {
SatelliteCount: 1, StorageNodeCount: 4, UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
config.Metainfo.ProjectLimits.DefaultMaxUsage = 1 * memory.MB
config.Metainfo.ProjectLimits.DefaultMaxBandwidth = 1 * memory.MB
config.Console.UsageLimits.DefaultStorageLimit = 1 * memory.MB
config.Console.UsageLimits.DefaultBandwidthLimit = 1 * memory.MB
},
},
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
Expand Down
26 changes: 6 additions & 20 deletions satellite/admin/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,20 +109,6 @@ func (server *Server) getProjectLimit(w http.ResponseWriter, r *http.Request) {
return
}

usagelimit, err := server.db.ProjectAccounting().GetProjectStorageLimit(ctx, projectUUID)
if err != nil {
httpJSONError(w, "failed to get usage limit",
err.Error(), http.StatusInternalServerError)
return
}

bandwidthlimit, err := server.db.ProjectAccounting().GetProjectBandwidthLimit(ctx, projectUUID)
if err != nil {
httpJSONError(w, "failed to get bandwidth limit",
err.Error(), http.StatusInternalServerError)
return
}

project, err := server.db.Console().Projects().Get(ctx, projectUUID)
if err != nil {
httpJSONError(w, "failed to get project",
Expand All @@ -144,13 +130,13 @@ func (server *Server) getProjectLimit(w http.ResponseWriter, r *http.Request) {
} `json:"rate"`
Buckets int `json:"maxBuckets"`
}
if usagelimit != nil {
output.Usage.Amount = memory.Size(*usagelimit)
output.Usage.Bytes = *usagelimit
if project.StorageLimit != nil {
output.Usage.Amount = *project.StorageLimit
output.Usage.Bytes = project.StorageLimit.Int64()
}
if bandwidthlimit != nil {
output.Bandwidth.Amount = memory.Size(*bandwidthlimit)
output.Bandwidth.Bytes = *bandwidthlimit
if project.BandwidthLimit != nil {
output.Bandwidth.Amount = *project.BandwidthLimit
output.Bandwidth.Bytes = project.BandwidthLimit.Int64()
}
if project.MaxBuckets != nil {
output.Buckets = *project.MaxBuckets
Expand Down
8 changes: 4 additions & 4 deletions satellite/admin/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestAPI(t *testing.T) {
t.Run("GetProject", func(t *testing.T) {
require.NoError(t, err)
expected := fmt.Sprintf(
`{"id":"%s","name":"%s","description":"%s","partnerId":"%s","ownerId":"%s","rateLimit":null,"maxBuckets":null,"createdAt":"%s","memberCount":0}`,
`{"id":"%s","name":"%s","description":"%s","partnerId":"%s","ownerId":"%s","rateLimit":null,"maxBuckets":null,"createdAt":"%s","memberCount":0,"storageLimit":"25.00 GB","bandwidthLimit":"25.00 GB"}`,
project.ID.String(),
project.Name,
project.Description,
Expand All @@ -60,7 +60,7 @@ func TestAPI(t *testing.T) {
})

t.Run("GetProjectLimits", func(t *testing.T) {
assertGet(t, linkLimit, `{"usage":{"amount":"0 B","bytes":0},"bandwidth":{"amount":"0 B","bytes":0},"rate":{"rps":0},"maxBuckets":0}`, planet.Satellites[0].Config.Console.AuthToken)
assertGet(t, linkLimit, `{"usage":{"amount":"25.00 GB","bytes":25000000000},"bandwidth":{"amount":"25.00 GB","bytes":25000000000},"rate":{"rps":0},"maxBuckets":0}`, planet.Satellites[0].Config.Console.AuthToken)
})

t.Run("UpdateUsage", func(t *testing.T) {
Expand All @@ -75,7 +75,7 @@ func TestAPI(t *testing.T) {
require.Equal(t, http.StatusOK, response.StatusCode)
require.NoError(t, response.Body.Close())

assertGet(t, linkLimit, `{"usage":{"amount":"1.0 TiB","bytes":1099511627776},"bandwidth":{"amount":"0 B","bytes":0},"rate":{"rps":0},"maxBuckets":0}`, planet.Satellites[0].Config.Console.AuthToken)
assertGet(t, linkLimit, `{"usage":{"amount":"1.0 TiB","bytes":1099511627776},"bandwidth":{"amount":"25.00 GB","bytes":25000000000},"rate":{"rps":0},"maxBuckets":0}`, planet.Satellites[0].Config.Console.AuthToken)

req, err = http.NewRequest(http.MethodPut, linkLimit+"?usage=1GB", nil)
require.NoError(t, err)
Expand All @@ -86,7 +86,7 @@ func TestAPI(t *testing.T) {
require.Equal(t, http.StatusOK, response.StatusCode)
require.NoError(t, response.Body.Close())

assertGet(t, linkLimit, `{"usage":{"amount":"1.00 GB","bytes":1000000000},"bandwidth":{"amount":"0 B","bytes":0},"rate":{"rps":0},"maxBuckets":0}`, planet.Satellites[0].Config.Console.AuthToken)
assertGet(t, linkLimit, `{"usage":{"amount":"1.00 GB","bytes":1000000000},"bandwidth":{"amount":"25.00 GB","bytes":25000000000},"rate":{"rps":0},"maxBuckets":0}`, planet.Satellites[0].Config.Console.AuthToken)
})

t.Run("UpdateBandwidth", func(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions satellite/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB,

{ // setup project limits
peer.ProjectLimits.Cache = accounting.NewProjectLimitCache(peer.DB.ProjectAccounting(),
config.Metainfo.ProjectLimits.DefaultMaxUsage,
config.Metainfo.ProjectLimits.DefaultMaxBandwidth,
config.Console.Config.UsageLimits.DefaultStorageLimit,
config.Console.Config.UsageLimits.DefaultBandwidthLimit,
config.ProjectLimit,
)
}
Expand Down
25 changes: 17 additions & 8 deletions satellite/console/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"errors"
"time"

"storj.io/common/memory"
"storj.io/common/uuid"
)

Expand Down Expand Up @@ -45,18 +46,26 @@ type Projects interface {
UpdateBucketLimit(ctx context.Context, id uuid.UUID, newLimit int) error
}

// UsageLimitsConfig is a configuration struct for default per-project usage limits.
type UsageLimitsConfig struct {
DefaultStorageLimit memory.Size `help:"the default storage usage limit" default:"50.00GB"`
DefaultBandwidthLimit memory.Size `help:"the default bandwidth usage limit" default:"50.00GB"`
}

// Project is a database object that describes Project entity.
type Project struct {
ID uuid.UUID `json:"id"`

Name string `json:"name"`
Description string `json:"description"`
PartnerID uuid.UUID `json:"partnerId"`
OwnerID uuid.UUID `json:"ownerId"`
RateLimit *int `json:"rateLimit"`
MaxBuckets *int `json:"maxBuckets"`
CreatedAt time.Time `json:"createdAt"`
MemberCount int `json:"memberCount"`
Name string `json:"name"`
Description string `json:"description"`
PartnerID uuid.UUID `json:"partnerId"`
OwnerID uuid.UUID `json:"ownerId"`
RateLimit *int `json:"rateLimit"`
MaxBuckets *int `json:"maxBuckets"`
CreatedAt time.Time `json:"createdAt"`
MemberCount int `json:"memberCount"`
StorageLimit *memory.Size `json:"storageLimit"`
BandwidthLimit *memory.Size `json:"bandwidthLimit"`
}

// ProjectInfo holds data needed to create/update Project.
Expand Down
15 changes: 10 additions & 5 deletions satellite/console/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ type Service struct {
type Config struct {
PasswordCost int `help:"password hashing cost (0=automatic)" internal:"true"`
OpenRegistrationEnabled bool `help:"enable open registration" default:"false"`
DefaultProjectLimit int `help:"default project limits for users" default:"10"`
DefaultProjectLimit int `help:"default project limits for users" default:"3"`
UsageLimits UsageLimitsConfig
}

// PaymentsService separates all payment related functionality.
Expand Down Expand Up @@ -573,6 +574,8 @@ func (s *Service) CreateUser(ctx context.Context, user CreateUser, tokenSecret R

if registrationToken != nil {
newUser.ProjectLimit = registrationToken.ProjectLimit
} else {
newUser.ProjectLimit = s.config.DefaultProjectLimit
}

u, err = tx.Users().Insert(ctx,
Expand Down Expand Up @@ -1003,10 +1006,12 @@ func (s *Service) CreateProject(ctx context.Context, projectInfo ProjectInfo) (p
err = s.store.WithTx(ctx, func(ctx context.Context, tx DBTx) error {
p, err = tx.Projects().Insert(ctx,
&Project{
Description: projectInfo.Description,
Name: projectInfo.Name,
OwnerID: auth.User.ID,
PartnerID: auth.User.PartnerID,
Description: projectInfo.Description,
Name: projectInfo.Name,
OwnerID: auth.User.ID,
PartnerID: auth.User.PartnerID,
StorageLimit: &s.config.UsageLimits.DefaultStorageLimit,
BandwidthLimit: &s.config.UsageLimits.DefaultBandwidthLimit,
},
)
if err != nil {
Expand Down
4 changes: 1 addition & 3 deletions satellite/metainfo/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,7 @@ type RateLimiterConfig struct {

// ProjectLimitConfig is a configuration struct for default project limits.
type ProjectLimitConfig struct {
MaxBuckets int `help:"max bucket count for a project." default:"100"`
DefaultMaxUsage memory.Size `help:"the default storage usage limit" default:"500.00GB"`
DefaultMaxBandwidth memory.Size `help:"the default bandwidth usage limit" default:"500.00GB"`
MaxBuckets int `help:"max bucket count for a project." default:"100"`
}

// Config is a configuration struct that is everything you need to start a metainfo.
Expand Down
11 changes: 11 additions & 0 deletions satellite/satellitedb/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,17 @@ func (db *satelliteDB) PostgresMigration() *migrate.Migration {
`ALTER TABLE nodes DROP COLUMN uptime_reputation_beta;`,
},
},
{
DB: &db.migrationDB,
Description: "set default project and usage limits on existing users",
Version: 151,
Action: migrate.SQL{
`UPDATE users SET project_limit = 10 WHERE project_limit = 0;`,
// 500 GB = 5e11 bytes
`UPDATE projects SET usage_limit = 500000000000 WHERE usage_limit IS NULL;`,
`UPDATE projects SET bandwidth_limit = 500000000000 WHERE bandwidth_limit IS NULL;`,
},
},
// NB: after updating testdata in `testdata`, run
// `go generate` to update `migratez.go`.
},
Expand Down
2 changes: 1 addition & 1 deletion satellite/satellitedb/migratez.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func (db *satelliteDB) testMigration() *migrate.Migration {
{
DB: &db.migrationDB,
Description: "Testing setup",
Version: 150,
Version: 151,
Action: migrate.SQL{`-- AUTOGENERATED BY storj.io/dbx
-- DO NOT EDIT
CREATE TABLE accounting_rollups (
Expand Down
25 changes: 17 additions & 8 deletions satellite/satellitedb/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/zeebo/errs"

"storj.io/common/memory"
"storj.io/common/uuid"
"storj.io/storj/satellite/console"
"storj.io/storj/satellite/satellitedb/dbx"
Expand Down Expand Up @@ -96,6 +97,12 @@ func (projects *projects) Insert(ctx context.Context, project *console.Project)
if !project.PartnerID.IsZero() {
createFields.PartnerId = dbx.Project_PartnerId(project.PartnerID[:])
}
if project.StorageLimit != nil {
createFields.UsageLimit = dbx.Project_UsageLimit(project.StorageLimit.Int64())
}
if project.BandwidthLimit != nil {
createFields.BandwidthLimit = dbx.Project_BandwidthLimit(project.BandwidthLimit.Int64())
}
createFields.RateLimit = dbx.Project_RateLimit_Raw(project.RateLimit)
createFields.MaxBuckets = dbx.Project_MaxBuckets_Raw(project.MaxBuckets)

Expand Down Expand Up @@ -304,14 +311,16 @@ func projectFromDBX(ctx context.Context, project *dbx.Project) (_ *console.Proje
}

return &console.Project{
ID: id,
Name: project.Name,
Description: project.Description,
PartnerID: partnerID,
OwnerID: ownerID,
RateLimit: project.RateLimit,
MaxBuckets: project.MaxBuckets,
CreatedAt: project.CreatedAt,
ID: id,
Name: project.Name,
Description: project.Description,
PartnerID: partnerID,
OwnerID: ownerID,
RateLimit: project.RateLimit,
MaxBuckets: project.MaxBuckets,
CreatedAt: project.CreatedAt,
StorageLimit: (*memory.Size)(project.UsageLimit),
BandwidthLimit: (*memory.Size)(project.BandwidthLimit),
}, nil
}

Expand Down
2 changes: 1 addition & 1 deletion satellite/satellitedb/testdata/postgres.v150.sql
Original file line number Diff line number Diff line change
Expand Up @@ -573,4 +573,4 @@ INSERT INTO "users"("id", "full_name", "short_name", "email", "normalized_email"

INSERT INTO "coupon_codes" ("id", "name", "amount", "description", "type", "duration", "created_at") VALUES (E'\\362\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014'::bytea, 'STORJ50', 50, '$50 for your first 5 months', 0, 2, '2019-06-01 08:28:24.267934+00');

-- NEW DATA --
-- NEW DATA --

0 comments on commit 27bcb46

Please sign in to comment.