Add system activity tracking and event store (#636)

This PR adds system activity tracking. 
The management service records events like 
add/remove peer,  group, rule, route, etc.

The activity events are stored in the SQLite event store
and can be queried by the HTTP API.
This commit is contained in:
Misha Bragin
2023-01-02 15:11:32 +01:00
committed by GitHub
parent 50caacff69
commit 5c0b8a46f0
42 changed files with 1827 additions and 227 deletions

View File

@@ -1,6 +1,11 @@
package server
import "github.com/netbirdio/netbird/management/server/status"
import (
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/status"
log "github.com/sirupsen/logrus"
"time"
)
// Group of the peers for ACL
type Group struct {
@@ -34,6 +39,11 @@ type GroupUpdateOperation struct {
Values []string
}
// EventMeta returns activity event meta related to the group
func (g *Group) EventMeta() map[string]any {
return map[string]any{"name": g.Name}
}
func (g *Group) Copy() *Group {
return &Group{
ID: g.ID,
@@ -62,7 +72,7 @@ func (am *DefaultAccountManager) GetGroup(accountID, groupID string) (*Group, er
}
// SaveGroup object of the peers
func (am *DefaultAccountManager) SaveGroup(accountID string, group *Group) error {
func (am *DefaultAccountManager) SaveGroup(accountID, userID string, newGroup *Group) error {
unlock := am.Store.AcquireAccountLock(accountID)
defer unlock()
@@ -71,17 +81,95 @@ func (am *DefaultAccountManager) SaveGroup(accountID string, group *Group) error
if err != nil {
return err
}
account.Groups[group.ID] = group
oldGroup, exists := account.Groups[newGroup.ID]
account.Groups[newGroup.ID] = newGroup
account.Network.IncSerial()
if err = am.Store.SaveAccount(account); err != nil {
return err
}
if !exists {
_, err = am.eventStore.Save(&activity.Event{
Timestamp: time.Now(),
Activity: activity.GroupCreated,
InitiatorID: userID,
TargetID: newGroup.ID,
AccountID: accountID,
Meta: newGroup.EventMeta(),
})
if err != nil {
return err
}
}
addedPeers := make([]string, 0)
removedPeers := make([]string, 0)
if !exists {
addedPeers = append(addedPeers, newGroup.Peers...)
} else {
addedPeers = difference(newGroup.Peers, oldGroup.Peers)
removedPeers = difference(oldGroup.Peers, newGroup.Peers)
}
for _, p := range addedPeers {
peer := account.Peers[p]
if peer == nil {
log.Errorf("peer %s not found under account %s while saving group", p, accountID)
continue
}
_, err = am.eventStore.Save(&activity.Event{
Timestamp: time.Now(),
Activity: activity.GroupAddedToPeer,
InitiatorID: userID,
TargetID: peer.IP.String(),
AccountID: accountID,
Meta: map[string]any{"group": newGroup.Name, "group_id": newGroup.ID, "peer_ip": peer.IP.String(),
"peer_fqdn": peer.FQDN(am.GetDNSDomain())},
})
if err != nil {
return err
}
}
for _, p := range removedPeers {
peer := account.Peers[p]
if peer == nil {
log.Errorf("peer %s not found under account %s while saving group", p, accountID)
continue
}
_, err = am.eventStore.Save(&activity.Event{
Timestamp: time.Now(),
Activity: activity.GroupRemovedFromPeer,
InitiatorID: userID,
TargetID: peer.IP.String(),
AccountID: accountID,
Meta: map[string]any{"group": newGroup.Name, "group_id": newGroup.ID, "peer_ip": peer.IP.String(),
"peer_fqdn": peer.FQDN(am.GetDNSDomain())},
})
if err != nil {
return err
}
}
return am.updateAccountPeers(account)
}
// difference returns the elements in `a` that aren't in `b`.
func difference(a, b []string) []string {
mb := make(map[string]struct{}, len(b))
for _, x := range b {
mb[x] = struct{}{}
}
var diff []string
for _, x := range a {
if _, found := mb[x]; !found {
diff = append(diff, x)
}
}
return diff
}
// UpdateGroup updates a group using a list of operations
func (am *DefaultAccountManager) UpdateGroup(accountID string,
groupID string, operations []GroupUpdateOperation) (*Group, error) {