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:
Fadila Khadar 2021-06-03 11:09:25 +02:00 committed by Fadila
parent c9cfb5ed0c
commit 3de9655b68
3 changed files with 65 additions and 5 deletions

View File

@ -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"
}

View File

@ -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)
})

View File

@ -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