Skip to content

Commit

Permalink
satellite/console: return placement info with bucket usages
Browse files Browse the repository at this point in the history
This change adds default placement and location to
accounting.BucketUsage so the bucket location can be displayed
in the satellite UI.

issue: #6685

Change-Id: I11fc4a678ae963da9e7087f680e9e070d016cc19
  • Loading branch information
cam-a authored and Storj Robot committed Feb 6, 2024
1 parent 560c9cf commit 68dafd5
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 10 deletions.
3 changes: 3 additions & 0 deletions satellite/accounting/db.go
Expand Up @@ -116,6 +116,9 @@ type BucketUsage struct {
ProjectID uuid.UUID `json:"projectID"`
BucketName string `json:"bucketName"`

DefaultPlacement storj.PlacementConstraint `json:"defaultPlacement"`
Location string `json:"location"`

Versioning buckets.Versioning `json:"versioning"`

Storage float64 `json:"storage"`
Expand Down
26 changes: 26 additions & 0 deletions satellite/accounting/projectusage_test.go
Expand Up @@ -21,8 +21,10 @@ import (
"go.uber.org/zap"
"golang.org/x/sync/errgroup"

"storj.io/common/macaroon"
"storj.io/common/memory"
"storj.io/common/pb"
"storj.io/common/storj"
"storj.io/common/sync2"
"storj.io/common/testcontext"
"storj.io/common/testrand"
Expand Down Expand Up @@ -839,6 +841,30 @@ func TestUsageRollups(t *testing.T) {
require.Equal(t, satbuckets.VersioningSuspended, usage.Versioning)
}
})

t.Run("placement", func(t *testing.T) {
bList, err := db.Buckets().ListBuckets(ctx, planet.Uplinks[0].Projects[0].ID, satbuckets.ListOptions{Direction: satbuckets.DirectionForward}, macaroon.AllowedBuckets{All: true})
require.NoError(t, err)
for _, b := range bList.Items {
// this is a number. See earlier in test where bucket is created
elems := strings.Split(b.Name, "-")
n, err := strconv.Atoi(elems[1])
require.NoError(t, err)
b.Placement = storj.PlacementConstraint(n)
_, err = db.Buckets().UpdateBucket(ctx, b)
require.NoError(t, err)
}
page, err := usageRollups.GetBucketTotals(ctx, planet.Uplinks[0].Projects[0].ID, accounting.BucketUsageCursor{Limit: 100, Page: 1}, time.Now())
require.NoError(t, err)
require.NotNil(t, page)
for _, b := range page.BucketUsages {
// this is a number. See earlier in test where bucket is created
elems := strings.Split(b.BucketName, "-")
n, err := strconv.Atoi(elems[1])
require.NoError(t, err)
require.True(t, int(b.DefaultPlacement) == n)
}
})
})
}

Expand Down
1 change: 1 addition & 0 deletions satellite/api.go
Expand Up @@ -600,6 +600,7 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB,
externalAddress,
consoleConfig.SatelliteName,
config.Metainfo.ProjectLimits.MaxBuckets,
placement,
consoleConfig.Config,
)
if err != nil {
Expand Down
1 change: 0 additions & 1 deletion satellite/console/consoleweb/server.go
Expand Up @@ -265,7 +265,6 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, oidc
}

router.Handle("/api/v0/config", server.withCORS(http.HandlerFunc(server.frontendConfigHandler)))

router.HandleFunc("/registrationToken/", server.createRegistrationTokenHandler)
router.HandleFunc("/robots.txt", server.seoHandler)

Expand Down
14 changes: 14 additions & 0 deletions satellite/console/placements.go
@@ -0,0 +1,14 @@
// Copyright (C) 2024 Storj Labs, Inc.
// See LICENSE for copying information.

package console

import (
"storj.io/common/storj"
)

// Placement contains placement info.
type Placement struct {
ID storj.PlacementConstraint `json:"id"`
Location string `json:"location"`
}
14 changes: 13 additions & 1 deletion satellite/console/service.go
Expand Up @@ -40,6 +40,7 @@ import (
"storj.io/storj/satellite/buckets"
"storj.io/storj/satellite/console/consoleauth"
"storj.io/storj/satellite/mailservice"
"storj.io/storj/satellite/nodeselection"
"storj.io/storj/satellite/payments"
"storj.io/storj/satellite/payments/billing"
"storj.io/storj/satellite/satellitedb/dbx"
Expand Down Expand Up @@ -181,6 +182,7 @@ type Service struct {
projectAccounting accounting.ProjectAccounting
projectUsage *accounting.Service
buckets buckets.DB
placements nodeselection.PlacementDefinitions
accounts payments.Accounts
depositWallets payments.DepositWallets
billing billing.TransactionsDB
Expand Down Expand Up @@ -218,7 +220,7 @@ type Payments struct {
}

// NewService returns new instance of Service.
func NewService(log *zap.Logger, store DB, restKeys RESTKeys, projectAccounting accounting.ProjectAccounting, projectUsage *accounting.Service, buckets buckets.DB, accounts payments.Accounts, depositWallets payments.DepositWallets, billing billing.TransactionsDB, analytics *analytics.Service, tokens *consoleauth.Service, mailService *mailservice.Service, accountFreezeService *AccountFreezeService, satelliteAddress string, satelliteName string, maxProjectBuckets int, config Config) (*Service, error) {
func NewService(log *zap.Logger, store DB, restKeys RESTKeys, projectAccounting accounting.ProjectAccounting, projectUsage *accounting.Service, buckets buckets.DB, accounts payments.Accounts, depositWallets payments.DepositWallets, billing billing.TransactionsDB, analytics *analytics.Service, tokens *consoleauth.Service, mailService *mailservice.Service, accountFreezeService *AccountFreezeService, satelliteAddress string, satelliteName string, maxProjectBuckets int, placements nodeselection.PlacementDefinitions, config Config) (*Service, error) {
if store == nil {
return nil, errs.New("store can't be nil")
}
Expand Down Expand Up @@ -254,6 +256,7 @@ func NewService(log *zap.Logger, store DB, restKeys RESTKeys, projectAccounting
projectAccounting: projectAccounting,
projectUsage: projectUsage,
buckets: buckets,
placements: placements,
accounts: accounts,
depositWallets: depositWallets,
billing: billing,
Expand Down Expand Up @@ -2818,6 +2821,15 @@ func (s *Service) GetBucketTotals(ctx context.Context, projectID uuid.UUID, curs
return nil, Error.Wrap(err)
}

if usage == nil {
return usage, nil
}

for i := range usage.BucketUsages {
placementID := usage.BucketUsages[i].DefaultPlacement
usage.BucketUsages[i].Location = s.placements[placementID].Name
}

return usage, nil
}

Expand Down
30 changes: 30 additions & 0 deletions satellite/console/service_test.go
Expand Up @@ -33,9 +33,11 @@ import (
"storj.io/storj/private/post"
"storj.io/storj/private/testplanet"
"storj.io/storj/satellite"
"storj.io/storj/satellite/accounting"
"storj.io/storj/satellite/buckets"
"storj.io/storj/satellite/console"
"storj.io/storj/satellite/console/consoleweb/consoleapi"
"storj.io/storj/satellite/nodeselection"
"storj.io/storj/satellite/payments"
"storj.io/storj/satellite/payments/billing"
"storj.io/storj/satellite/payments/coinpayments"
Expand All @@ -45,11 +47,20 @@ import (
)

func TestService(t *testing.T) {
placements := make(map[int]string)
for i := 0; i < 4; i++ {
placements[i] = fmt.Sprintf("loc-%d", i)
}
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 1, UplinkCount: 3,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
config.Payments.StripeCoinPayments.StripeFreeTierCouponID = stripe.MockCouponID1
var plcStr string
for k, v := range placements {
plcStr += fmt.Sprintf(`%d:annotation("location", "%s"); `, k, v)
}
config.Placement = nodeselection.ConfigurablePlacementRule{PlacementRules: plcStr}
},
},
},
Expand Down Expand Up @@ -653,6 +664,25 @@ func TestService(t *testing.T) {
require.Nil(t, bucketsForUnauthorizedUser)
})

t.Run("GetBucketTotals", func(t *testing.T) {
list, err := sat.DB.Buckets().ListBuckets(ctx, up2Proj.ID, buckets.ListOptions{Direction: buckets.DirectionForward}, macaroon.AllowedBuckets{All: true})
require.NoError(t, err)
for i, item := range list.Items {
item.Placement = storj.PlacementConstraint(i)
if i > len(placements)-1 {
item.Placement = storj.PlacementConstraint(len(placements) - 1)
}
b, err := sat.DB.Buckets().UpdateBucket(ctx, item)
require.NoError(t, err)
require.Equal(t, i, int(b.Placement))
}
bt, err := service.GetBucketTotals(userCtx2, up2Proj.ID, accounting.BucketUsageCursor{Limit: 100, Page: 1}, time.Now())
require.NoError(t, err)
for _, b := range bt.BucketUsages {
require.Equal(t, placements[int(b.DefaultPlacement)], b.Location)
}
})

t.Run("DeleteAPIKeyByNameAndProjectID", func(t *testing.T) {
secret, err := macaroon.NewSecret()
require.NoError(t, err)
Expand Down
2 changes: 2 additions & 0 deletions satellite/payments/stripe/accounts_test.go
Expand Up @@ -19,6 +19,7 @@ import (
"storj.io/storj/satellite/console"
"storj.io/storj/satellite/console/consoleauth"
"storj.io/storj/satellite/console/restkeys"
"storj.io/storj/satellite/nodeselection"
"storj.io/storj/satellite/payments"
"storj.io/storj/satellite/payments/paymentsconfig"
"storj.io/storj/satellite/payments/stripe"
Expand Down Expand Up @@ -96,6 +97,7 @@ func TestSignupCouponCodes(t *testing.T) {
"",
"",
sat.Config.Metainfo.ProjectLimits.MaxBuckets,
nodeselection.NewPlacementDefinitions(),
console.Config{PasswordCost: console.TestPasswordCost, DefaultProjectLimit: 5},
)

Expand Down
19 changes: 12 additions & 7 deletions satellite/satellitedb/projectaccounting.go
Expand Up @@ -20,6 +20,7 @@ import (
"storj.io/common/dbutil/pgxutil"
"storj.io/common/memory"
"storj.io/common/pb"
"storj.io/common/storj"
"storj.io/common/tagsql"
"storj.io/common/useragent"
"storj.io/common/uuid"
Expand Down Expand Up @@ -894,7 +895,7 @@ func (db *ProjectAccounting) GetBucketTotals(ctx context.Context, projectID uuid
return nil, errs.New("page is out of range")
}

bucketsQuery := db.db.Rebind(`SELECT name, versioning, created_at FROM bucket_metainfos
bucketsQuery := db.db.Rebind(`SELECT name, versioning, placement, created_at FROM bucket_metainfos
WHERE project_id = ? AND ` + bucketNameRange + `ORDER BY name ASC LIMIT ? OFFSET ?`)

args = []interface{}{
Expand All @@ -915,6 +916,7 @@ func (db *ProjectAccounting) GetBucketTotals(ctx context.Context, projectID uuid
type bucketWithCreationDate struct {
name string
versioning satbuckets.Versioning
placement storj.PlacementConstraint
createdAt time.Time
}

Expand All @@ -923,16 +925,18 @@ func (db *ProjectAccounting) GetBucketTotals(ctx context.Context, projectID uuid
var (
bucket string
versioning satbuckets.Versioning
placement storj.PlacementConstraint
createdAt time.Time
)
err = bucketRows.Scan(&bucket, &versioning, &createdAt)
err = bucketRows.Scan(&bucket, &versioning, &placement, &createdAt)
if err != nil {
return nil, err
}

buckets = append(buckets, bucketWithCreationDate{
name: bucket,
versioning: versioning,
placement: placement,
createdAt: createdAt,
})
}
Expand All @@ -953,11 +957,12 @@ func (db *ProjectAccounting) GetBucketTotals(ctx context.Context, projectID uuid
var bucketUsages []accounting.BucketUsage
for _, bucket := range buckets {
bucketUsage := accounting.BucketUsage{
ProjectID: projectID,
BucketName: bucket.name,
Versioning: bucket.versioning,
Since: bucket.createdAt,
Before: before,
ProjectID: projectID,
BucketName: bucket.name,
Versioning: bucket.versioning,
DefaultPlacement: bucket.placement,
Since: bucket.createdAt,
Before: before,
}

// get bucket_bandwidth_rollups
Expand Down
2 changes: 1 addition & 1 deletion web/satellite/src/store/modules/appStore.ts
Expand Up @@ -24,7 +24,7 @@ class ErrorPageState {
public statusCode = 0,
public fatal = false,
public visible = false,
) {}
) { }
}

export const useAppStore = defineStore('app', () => {
Expand Down

0 comments on commit 68dafd5

Please sign in to comment.