satellite/redis: used bandwidth key depends on day
The redis key associated to bandwidth usage depended on the current month. This change makes it depends also on the day, so that we update bandwidth usage daily to take into account changes associated to expired but not used allocated bandwidth. It also add a test to to check that the allocated but not settled bandwidth is not counted after 2 days. Change-Id: Iee9dbe3517cc3b9825438360b276a07a43dfbc64
This commit is contained in:
parent
c9cfb5ed0c
commit
3de9655b68
@ -203,6 +203,6 @@ func (cache *redisLiveAccounting) getInt64(ctx context.Context, key string) (_ i
|
||||
// The current month is combined with projectID to create a prefix.
|
||||
func createBandwidthProjectIDKey(projectID uuid.UUID, now time.Time) string {
|
||||
// Add current month as prefix
|
||||
_, month, _ := now.Date()
|
||||
return string(projectID[:]) + string(byte(month)) + ":bandwidth"
|
||||
_, month, day := now.Date()
|
||||
return string(projectID[:]) + string(byte(month)) + string(byte(day)) + ":bandwidth"
|
||||
}
|
||||
|
@ -622,6 +622,56 @@ func TestProjectUsage_FreeUsedStorageSpace(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestProjectUsageBandwidthResetAfter3days(t *testing.T) {
|
||||
testplanet.Run(t, testplanet.Config{
|
||||
SatelliteCount: 1, StorageNodeCount: 4, UplinkCount: 1,
|
||||
Reconfigure: testplanet.Reconfigure{
|
||||
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
|
||||
config.Console.UsageLimits.DefaultStorageLimit = 1 * memory.MB
|
||||
config.Console.UsageLimits.DefaultBandwidthLimit = 1 * memory.MB
|
||||
},
|
||||
},
|
||||
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
||||
|
||||
orderDB := planet.Satellites[0].DB.Orders()
|
||||
bucket := metabase.BucketLocation{ProjectID: planet.Uplinks[0].Projects[0].ID, BucketName: "testbucket"}
|
||||
projectUsage := planet.Satellites[0].Accounting.ProjectUsage
|
||||
|
||||
now := time.Now()
|
||||
|
||||
allocationTime := time.Date(now.Year(), now.Month(), 2, now.Hour(), now.Minute(), now.Second(), now.Nanosecond(), now.Location())
|
||||
|
||||
amount := 1 * memory.MB.Int64()
|
||||
err := orderDB.UpdateBucketBandwidthAllocation(ctx, bucket.ProjectID, []byte(bucket.BucketName), pb.PieceAction_GET, amount, allocationTime)
|
||||
require.NoError(t, err)
|
||||
|
||||
beforeResetDay := allocationTime.Add(2 * time.Hour * 24)
|
||||
resetDay := allocationTime.Add(3 * time.Hour * 24)
|
||||
endOfMonth := time.Date(now.Year(), now.Month()+1, 0, now.Hour(), now.Minute(), now.Second(), now.Nanosecond(), now.Location())
|
||||
|
||||
for _, tt := range []struct {
|
||||
description string
|
||||
now time.Time
|
||||
expectedExceeds bool
|
||||
}{
|
||||
{"allocation day", allocationTime, true},
|
||||
{"day before reset", beforeResetDay, true},
|
||||
{"reset day", resetDay, false},
|
||||
{"end of month", endOfMonth, false},
|
||||
} {
|
||||
projectUsage.SetNow(func() time.Time {
|
||||
return tt.now
|
||||
})
|
||||
|
||||
actualExceeded, _, err := projectUsage.ExceedsBandwidthUsage(ctx, bucket.ProjectID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.expectedExceeds, actualExceeded, tt.description)
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestProjectUsage_ResetLimitsFirstDayOfNextMonth(t *testing.T) {
|
||||
testplanet.Run(t, testplanet.Config{
|
||||
SatelliteCount: 1, StorageNodeCount: 4, UplinkCount: 1,
|
||||
@ -737,12 +787,22 @@ func TestProjectUsage_BandwidthDownloadLimit(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// send orders so we get the egress settled
|
||||
require.NoError(t, planet.WaitForStorageNodeEndpoints(ctx))
|
||||
tomorrow := time.Now().Add(24 * time.Hour)
|
||||
for _, storageNode := range planet.StorageNodes {
|
||||
storageNode.Storage2.Orders.SendOrders(ctx, tomorrow)
|
||||
}
|
||||
|
||||
planet.Satellites[0].Orders.Chore.Loop.TriggerWait()
|
||||
|
||||
// An extra download should return 'Exceeded Usage Limit' error
|
||||
_, err = planet.Uplinks[0].Download(ctx, planet.Satellites[0], "testbucket", "test/path1")
|
||||
require.Error(t, err)
|
||||
require.True(t, errors.Is(err, uplink.ErrBandwidthLimitExceeded))
|
||||
planet.Satellites[0].Orders.Chore.Loop.TriggerWait()
|
||||
|
||||
// Simulate new billing cycle (newxt month)
|
||||
// Simulate new billing cycle (next month)
|
||||
planet.Satellites[0].API.Accounting.ProjectUsage.SetNow(func() time.Time {
|
||||
return time.Date(now.Year(), now.Month()+1, 1, 0, 0, 0, 0, time.UTC)
|
||||
})
|
||||
|
@ -148,13 +148,13 @@ func (db *ProjectAccounting) GetProjectBandwidth(ctx context.Context, projectID
|
||||
if day < allocatedExpirationInDays {
|
||||
expiredSince = startOfMonth
|
||||
} else {
|
||||
expiredSince = time.Date(year, month, day-allocatedExpirationInDays+1, 0, 0, 0, 0, time.UTC)
|
||||
expiredSince = time.Date(year, month, day-allocatedExpirationInDays, 0, 0, 0, 0, time.UTC)
|
||||
}
|
||||
periodEnd := time.Date(year, month+1, 0, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
query := ` WITH egress AS (
|
||||
SELECT
|
||||
CASE WHEN interval_day <= ?
|
||||
CASE WHEN interval_day < ?
|
||||
THEN egress_settled
|
||||
ELSE egress_allocated
|
||||
END AS amount
|
||||
|
Loading…
Reference in New Issue
Block a user