Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VAULT-14735: generate mock clients for activity log #20252

Merged
merged 6 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 31 additions & 41 deletions vault/activity/generation/generate_data.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 5 additions & 6 deletions vault/activity/generation/generate_data.proto
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,9 @@ message Clients {
message Client {
string id = 1;
int32 count = 2;
int32 times_seen = 3;
bool repeated = 4;
int32 repeated_from_month = 5;
string namespace = 6;
string mount = 7;
bool non_entity = 8;
bool repeated = 3;
int32 repeated_from_month = 4;
string namespace = 5;
string mount = 6;
bool non_entity = 7;
}
125 changes: 125 additions & 0 deletions vault/logical_system_activity_write_testonly.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ package vault

import (
"context"
"errors"
"fmt"

"github.com/hashicorp/go-uuid"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault/activity"
"github.com/hashicorp/vault/vault/activity/generation"
"google.golang.org/protobuf/encoding/protojson"
)
Expand Down Expand Up @@ -51,3 +56,123 @@ func (b *SystemBackend) handleActivityWriteData(ctx context.Context, request *lo
}
return nil, nil
}

// singleMonthActivityClients holds a single month's client IDs, in the order they were seen
type singleMonthActivityClients struct {
// clients are indexed by ID
clients []*activity.EntityRecord
}

// multipleMonthsActivityClients holds multiple month's data
type multipleMonthsActivityClients struct {
// months are in order, with month 0 being the current month and index 1 being 1 month ago
months []*singleMonthActivityClients
}

// addNewClients generates clients according to the given parameters, and adds them to the month
// the client will always have the mountAccessor as its mount accessor
func (s *singleMonthActivityClients) addNewClients(c *generation.Client, mountAccessor string) error {
count := 1
if c.Count > 1 {
count = int(c.Count)
}
clientType := entityActivityType
if c.NonEntity {
clientType = nonEntityTokenActivityType
}
for i := 0; i < count; i++ {
record := &activity.EntityRecord{
ClientID: c.Id,
NamespaceID: c.Namespace,
NonEntity: c.NonEntity,
MountAccessor: mountAccessor,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can add the new ClientType field here, or do you think that's more deserving of a separate PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add it here

ClientType: clientType,
}
if record.ClientID == "" {
var err error
record.ClientID, err = uuid.GenerateUUID()
if err != nil {
return err
}
}
s.clients = append(s.clients, record)
}
return nil
}

// processMonth populates a month of client data
func (m *multipleMonthsActivityClients) processMonth(ctx context.Context, core *Core, month *generation.Data) error {
if month.GetAll() == nil {
return errors.New("segmented monthly data is not yet supported")
}

// default to using the root namespace and the first mount on the root namespace
mounts, err := core.ListMounts()
if err != nil {
return err
}
defaultMountAccessorRootNS := ""
for _, mount := range mounts {
miagilepner marked this conversation as resolved.
Show resolved Hide resolved
if mount.NamespaceID == namespace.RootNamespaceID {
defaultMountAccessorRootNS = mount.Accessor
break
}
}
addingTo := m.months[month.GetMonthsAgo()]

for _, clients := range month.GetAll().Clients {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit confused, is clients a single client? Shall we use client instead if it is indeed a single client?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clients is a single description of how to generate some number of clients. for example:

&Client{
	Count: 10,
	Namespace: "root",
	Mount: "kv",
}

could be the value, and it means generate 10 distinct clients with namespace "root" and mount "kv".

I can change the variable to client, if that's clearer

if clients.Repeated || clients.RepeatedFromMonth > 0 {
return errors.New("repeated clients are not yet supported")
}

if clients.Namespace == "" {
clients.Namespace = namespace.RootNamespaceID
}

// verify that the namespace exists
ns, err := core.NamespaceByID(ctx, clients.Namespace)
if err != nil {
return err
}

// verify that the mount exists
if clients.Mount != "" {
nctx := namespace.ContextWithNamespace(ctx, ns)
mountEntry := core.router.MatchingMountEntry(nctx, clients.Mount)
if mountEntry == nil {
return fmt.Errorf("unable to find matching mount in namespace %s", clients.Namespace)
}
}

mountAccessor := defaultMountAccessorRootNS
if clients.Namespace != namespace.RootNamespaceID && clients.Mount == "" {
// if we're not using the root namespace, find a mount on the namespace that we are using
found := false
for _, mount := range mounts {
if mount.NamespaceID == clients.Namespace {
mountAccessor = mount.Accessor
found = true
break
}
}
if !found {
return fmt.Errorf("unable to find matching mount in namespace %s", clients.Namespace)
}
}
err = addingTo.addNewClients(clients, mountAccessor)
if err != nil {
return err
}
}
return nil
}

func newMultipleMonthsActivityClients(numberOfMonths int) *multipleMonthsActivityClients {
m := &multipleMonthsActivityClients{
months: make([]*singleMonthActivityClients, numberOfMonths),
}
for i := 0; i < numberOfMonths; i++ {
m.months[i] = new(singleMonthActivityClients)
}
return m
}
Loading