Skip to content

Commit 56bfaa4

Browse files
committed
Revert "temp"
This reverts commit 4932979.
1 parent 4932979 commit 56bfaa4

File tree

2 files changed

+66
-203
lines changed

2 files changed

+66
-203
lines changed

vault/activity_log.go

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,29 +1830,54 @@ func (a *ActivityLog) handleQuery(ctx context.Context, startTime, endTime time.T
18301830
pq = storedQuery
18311831
}
18321832

1833+
// Calculate the namespace response breakdowns and totals for entities and tokens from the initial
1834+
// namespace data.
1835+
totalCounts, byNamespaceResponse, err := a.calculateByNamespaceResponseForQuery(ctx, pq.Namespaces)
1836+
if err != nil {
1837+
return nil, err
1838+
}
1839+
1840+
// If we need to add the current month's client counts into the total, compute the namespace
1841+
// breakdown for the current month as well.
18331842
var partialByMonth map[int64]*processMonth
1843+
var partialByNamespace map[string]*processByNamespace
1844+
var byNamespaceResponseCurrent []*ResponseNamespace
1845+
var totalCurrentCounts *ResponseCounts
18341846
if computePartial {
18351847
// Traverse through current month's activitylog data and group clients
18361848
// into months and namespaces
18371849
a.fragmentLock.RLock()
1838-
partialByMonth, _ = a.populateNamespaceAndMonthlyBreakdowns()
1850+
partialByMonth, partialByNamespace = a.populateNamespaceAndMonthlyBreakdowns()
18391851
a.fragmentLock.RUnlock()
18401852

1841-
// Estimate the current month totals. These record contains is complete with all the
1842-
// current month data, grouped by namespace and mounts
1843-
currentMonth, err := a.computeCurrentMonthForBillingPeriod(ctx, partialByMonth, startTime, endTime)
1853+
// Convert the byNamespace breakdowns into structs that are
1854+
// consumable by the /activity endpoint, so as to reuse code between these two
1855+
// endpoints.
1856+
byNamespaceComputation := a.transformALNamespaceBreakdowns(partialByNamespace)
1857+
1858+
// Calculate the namespace response breakdowns and totals for entities
1859+
// and tokens from current month namespace data.
1860+
totalCurrentCounts, byNamespaceResponseCurrent, err = a.calculateByNamespaceResponseForQuery(ctx, byNamespaceComputation)
18441861
if err != nil {
18451862
return nil, err
18461863
}
18471864

1848-
// Combine the existing months precomputed query with the current month data
1849-
pq.CombineWithCurrentMonth(currentMonth)
1850-
}
1865+
// Create a mapping of namespace id to slice index, so that we can efficiently update our results without
1866+
// having to traverse the entire namespace response slice every time.
1867+
nsrMap := make(map[string]int)
1868+
for i, nr := range byNamespaceResponse {
1869+
nsrMap[nr.NamespaceID] = i
1870+
}
18511871

1852-
// Convert the namespace data into a protobuf format that can be returned in the response
1853-
totalCounts, byNamespaceResponse, err := a.calculateByNamespaceResponseForQuery(ctx, pq.Namespaces)
1854-
if err != nil {
1855-
return nil, err
1872+
// Rather than blindly appending, which will create duplicates, check our existing counts against the current
1873+
// month counts, and append or update as necessary. We also want to account for mounts and their counts.
1874+
for _, nrc := range byNamespaceResponseCurrent {
1875+
if ndx, ok := nsrMap[nrc.NamespaceID]; ok {
1876+
byNamespaceResponse[ndx].Add(nrc)
1877+
} else {
1878+
byNamespaceResponse = append(byNamespaceResponse, nrc)
1879+
}
1880+
}
18561881
}
18571882

18581883
// Sort clients within each namespace
@@ -1862,6 +1887,34 @@ func (a *ActivityLog) handleQuery(ctx context.Context, startTime, endTime time.T
18621887
totalCounts, byNamespaceResponse = a.limitNamespacesInALResponse(byNamespaceResponse, limitNamespaces)
18631888
}
18641889

1890+
distinctEntitiesResponse := totalCounts.EntityClients
1891+
if computePartial {
1892+
currentMonth, err := a.computeCurrentMonthForBillingPeriod(ctx, partialByMonth, startTime, endTime)
1893+
if err != nil {
1894+
return nil, err
1895+
}
1896+
1897+
// Add the namespace attribution for the current month to the newly computed current month value. Note
1898+
// that transformMonthBreakdowns calculates a superstruct of the required namespace struct due to its
1899+
// primary use-case being for precomputedQueryWorker, but we will reuse this code for brevity and extract
1900+
// the namespaces from it.
1901+
currentMonthNamespaceAttribution := a.transformMonthBreakdowns(partialByMonth)
1902+
1903+
// Ensure that there is only one element in this list -- if not, warn.
1904+
if len(currentMonthNamespaceAttribution) > 1 {
1905+
a.logger.Warn("more than one month worth of namespace and mount attribution calculated for "+
1906+
"current month values", "number of months", len(currentMonthNamespaceAttribution))
1907+
}
1908+
if len(currentMonthNamespaceAttribution) == 0 {
1909+
a.logger.Warn("no month data found, returning query with no namespace attribution for current month")
1910+
} else {
1911+
currentMonth.Namespaces = currentMonthNamespaceAttribution[0].Namespaces
1912+
currentMonth.NewClients.Namespaces = currentMonthNamespaceAttribution[0].NewClients.Namespaces
1913+
}
1914+
pq.Months = append(pq.Months, currentMonth)
1915+
distinctEntitiesResponse += pq.Months[len(pq.Months)-1].NewClients.Counts.EntityClients
1916+
}
1917+
18651918
// Now populate the response based on breakdowns.
18661919
responseData := make(map[string]interface{})
18671920
responseData["start_time"] = pq.StartTime.Format(time.RFC3339)
@@ -1878,6 +1931,8 @@ func (a *ActivityLog) handleQuery(ctx context.Context, startTime, endTime time.T
18781931
}
18791932

18801933
responseData["by_namespace"] = byNamespaceResponse
1934+
totalCounts.Add(totalCurrentCounts)
1935+
totalCounts.DistinctEntities = distinctEntitiesResponse
18811936
responseData["total"] = totalCounts
18821937

18831938
// Create and populate the month response structs based on the monthly breakdown.

vault/activity_log_test.go

Lines changed: 0 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"encoding/json"
1010
"errors"
1111
"fmt"
12-
"math"
1312
"net/http"
1413
"os"
1514
"path/filepath"
@@ -26,7 +25,6 @@ import (
2625
"github.com/go-test/deep"
2726
"github.com/golang/protobuf/proto"
2827
"github.com/hashicorp/go-uuid"
29-
"github.com/hashicorp/vault/builtin/credential/userpass"
3028
"github.com/hashicorp/vault/helper/constants"
3129
"github.com/hashicorp/vault/helper/namespace"
3230
"github.com/hashicorp/vault/helper/timeutil"
@@ -5086,193 +5084,3 @@ func TestActivityLog_reportPrecomputedQueryMetrics(t *testing.T) {
50865084
hasMetric(t, data, "identity.pki_acme.active.reporting_period", 3, nil)
50875085
})
50885086
}
5089-
5090-
// TestHandleQuery_MultipleMounts creates a cluster with
5091-
// two userpass mounts. It then tests verifies that
5092-
// the total new counts are calculated within a reasonably level of accuracy for
5093-
// various numbers of clients in each mount.
5094-
func TestHandleQuery_MultipleMounts(t *testing.T) {
5095-
tests := map[string]struct {
5096-
twoMonthsAgo [][]int
5097-
oneMonthAgo [][]int
5098-
currentMonth [][]int
5099-
expectedNewClients int
5100-
repeatPreviousMonth bool
5101-
expectedTotalAccuracy float64
5102-
}{
5103-
"low volume, all mounts": {
5104-
twoMonthsAgo: [][]int{
5105-
{20, 20},
5106-
},
5107-
oneMonthAgo: [][]int{
5108-
{30, 30},
5109-
},
5110-
currentMonth: [][]int{
5111-
{40, 40},
5112-
},
5113-
repeatPreviousMonth: true,
5114-
expectedNewClients: 80,
5115-
expectedTotalAccuracy: 1,
5116-
},
5117-
"medium volume, all mounts": {
5118-
twoMonthsAgo: [][]int{
5119-
{200, 200},
5120-
},
5121-
oneMonthAgo: [][]int{
5122-
{300, 300},
5123-
},
5124-
currentMonth: [][]int{
5125-
{400, 400},
5126-
},
5127-
repeatPreviousMonth: true,
5128-
expectedNewClients: 800,
5129-
expectedTotalAccuracy: 0.98,
5130-
},
5131-
"higher volume, all mounts": {
5132-
twoMonthsAgo: [][]int{
5133-
{200, 200},
5134-
},
5135-
oneMonthAgo: [][]int{
5136-
{300, 300},
5137-
},
5138-
currentMonth: [][]int{
5139-
{2000, 5000},
5140-
},
5141-
repeatPreviousMonth: true,
5142-
expectedNewClients: 7000,
5143-
expectedTotalAccuracy: 0.95,
5144-
},
5145-
"higher volume, no repeats": {
5146-
twoMonthsAgo: [][]int{
5147-
{200, 200},
5148-
},
5149-
oneMonthAgo: [][]int{
5150-
{300, 300},
5151-
},
5152-
currentMonth: [][]int{
5153-
{4000, 6000},
5154-
},
5155-
repeatPreviousMonth: false,
5156-
expectedNewClients: 10000,
5157-
expectedTotalAccuracy: 0.98,
5158-
},
5159-
}
5160-
5161-
for i, tt := range tests {
5162-
testname := fmt.Sprintf("%s", i)
5163-
t.Run(testname, func(t *testing.T) {
5164-
// Normalize to start of month to prevent end of month weirdness
5165-
startOfMonth := timeutil.StartOfMonth(time.Now().UTC())
5166-
5167-
storage := &logical.InmemStorage{}
5168-
coreConfig := &CoreConfig{
5169-
CredentialBackends: map[string]logical.Factory{
5170-
"userpass": userpass.Factory,
5171-
},
5172-
Physical: storage.Underlying(),
5173-
}
5174-
5175-
cluster := NewTestCluster(t, coreConfig, nil)
5176-
cluster.Start()
5177-
defer cluster.Cleanup()
5178-
core := cluster.Cores[0].Core
5179-
TestWaitActive(t, core)
5180-
5181-
a := core.activityLog
5182-
ctx := namespace.RootContext(nil)
5183-
var err error
5184-
5185-
namespaces := make([]*namespace.Namespace, 0, 6)
5186-
mounts := make(map[string][]*MountEntry)
5187-
ns := namespace.RootNamespace
5188-
namespaces = append(namespaces, ns)
5189-
5190-
// Add two userpass mounts to the root namespace
5191-
for i := 0; i < 1; i++ {
5192-
me1 := &MountEntry{
5193-
Table: credentialTableType,
5194-
Path: "up1/",
5195-
Type: "userpass",
5196-
}
5197-
err = core.enableCredential(namespace.ContextWithNamespace(ctx, namespaces[i]), me1)
5198-
require.NoError(t, err)
5199-
5200-
me2 := &MountEntry{
5201-
Table: credentialTableType,
5202-
Path: "up2/",
5203-
Type: "userpass",
5204-
}
5205-
err = core.enableCredential(namespace.ContextWithNamespace(ctx, namespaces[i]), me2)
5206-
require.NoError(t, err)
5207-
mounts[namespaces[i].ID] = []*MountEntry{me1, me2}
5208-
}
5209-
5210-
// Generate data for two months ago
5211-
clientPrefix := 1
5212-
var entityRecordsMonth2 []*activity.EntityRecord
5213-
for namespaceId, mountSlice := range mounts {
5214-
for mountIndex, mount := range mountSlice {
5215-
entityRecordsMonth2 = append(entityRecordsMonth2, generateClientData(0, tt.twoMonthsAgo[0][mountIndex], mount.Accessor, namespaceId, fmt.Sprintf("%d", clientPrefix))...)
5216-
}
5217-
}
5218-
5219-
// Generate data for a month ago
5220-
clientPrefix += 1
5221-
var entityRecordsMonth1 []*activity.EntityRecord
5222-
for namespaceId, mountSlice := range mounts {
5223-
for mountIndex, mount := range mountSlice {
5224-
entityRecordsMonth2 = append(entityRecordsMonth1, generateClientData(0, tt.oneMonthAgo[0][mountIndex], mount.Accessor, namespaceId, fmt.Sprintf("%d", clientPrefix))...)
5225-
}
5226-
}
5227-
5228-
startOfTwoMonthsAgo := timeutil.StartOfMonth(startOfMonth.AddDate(0, -2, 0)).UTC()
5229-
startOfOneMonthAgo := timeutil.StartOfMonth(startOfMonth.AddDate(0, -1, 0)).UTC()
5230-
generatePreviousMonthClientData(t, core, startOfTwoMonthsAgo, entityRecordsMonth2)
5231-
generatePreviousMonthClientData(t, core, startOfOneMonthAgo, entityRecordsMonth1)
5232-
5233-
// Generate the current months data
5234-
clientPrefix += 1
5235-
var currentMonthData []*activity.EntityRecord
5236-
for namespaceId, mountSlice := range mounts {
5237-
for mountIndex, mount := range mountSlice {
5238-
currentMonthData = append(currentMonthData, generateClientData(0, tt.currentMonth[0][mountIndex], mount.Accessor, namespaceId, fmt.Sprintf("%d", clientPrefix))...)
5239-
clientPrefix += 1
5240-
mountIndex++
5241-
}
5242-
}
5243-
generateCurrentMonthClientData(t, core, entityRecordsMonth2, currentMonthData)
5244-
5245-
endOfCurrentMonth := timeutil.EndOfMonth(time.Now().UTC())
5246-
actual, err := a.handleQuery(ctx, startOfTwoMonthsAgo, endOfCurrentMonth, 0)
5247-
5248-
// Ensure that the month response is the same as the totals, because all clients
5249-
// are new clients and there will be no approximation in the single month partial
5250-
// case
5251-
monthsRaw, ok := actual["months"]
5252-
if !ok {
5253-
t.Fatalf("malformed results. got %v", actual)
5254-
}
5255-
monthsResponse := make([]ResponseMonth, 0)
5256-
err = mapstructure.Decode(monthsRaw, &monthsResponse)
5257-
5258-
currentMonthClients := monthsResponse[len(monthsResponse)-1]
5259-
5260-
// New verify that the new client totals for ALL namespaces are approximately accurate
5261-
newClientsError := math.Abs((float64)(currentMonthClients.NewClients.Counts.Clients - tt.expectedNewClients))
5262-
newClientsErrorMargin := newClientsError / (float64)(tt.expectedNewClients)
5263-
expectedAccuracyCalc := (1 - tt.expectedTotalAccuracy) * 100 / 100
5264-
if newClientsErrorMargin > expectedAccuracyCalc {
5265-
t.Fatalf("bad accuracy: expected %+v, found %+v", expectedAccuracyCalc, newClientsErrorMargin)
5266-
}
5267-
5268-
// Verify that the totals for the clients are visibly sensible (that is the total of all the individual new clients per namespace)
5269-
total := 0
5270-
for _, newClientCounts := range currentMonthClients.NewClients.Namespaces {
5271-
total += newClientCounts.Counts.Clients
5272-
}
5273-
if diff := math.Abs(float64(currentMonthClients.NewClients.Counts.Clients - total)); diff >= 1 {
5274-
t.Fatalf("total expected was %d but got %d", currentMonthClients.NewClients.Counts.Clients, total)
5275-
}
5276-
})
5277-
}
5278-
}

0 commit comments

Comments
 (0)