Add stack trace when saving empty domains (#2228)

added temporary domain check for existing accounts to trace where the issue originated

Refactor save account due to complexity score
This commit is contained in:
Maycon Santos 2024-07-02 12:40:26 +02:00 committed by GitHub
parent 4517da8b3a
commit eab6183a8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -7,6 +7,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"runtime/debug"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -30,6 +31,7 @@ import (
const ( const (
storeSqliteFileName = "store.db" storeSqliteFileName = "store.db"
idQueryCondition = "id = ?"
) )
// SqlStore represents an account storage backed by a Sql DB persisted to disk // SqlStore represents an account storage backed by a Sql DB persisted to disk
@ -128,38 +130,10 @@ func (s *SqlStore) AcquireAccountReadLock(accountID string) (unlock func()) {
func (s *SqlStore) SaveAccount(account *Account) error { func (s *SqlStore) SaveAccount(account *Account) error {
start := time.Now() start := time.Now()
for _, key := range account.SetupKeys { // todo: remove this check after the issue is resolved
account.SetupKeysG = append(account.SetupKeysG, *key) s.checkAccountDomainBeforeSave(account.Id, account.Domain)
}
for id, peer := range account.Peers { generateAccountSQLTypes(account)
peer.ID = id
account.PeersG = append(account.PeersG, *peer)
}
for id, user := range account.Users {
user.Id = id
for id, pat := range user.PATs {
pat.ID = id
user.PATsG = append(user.PATsG, *pat)
}
account.UsersG = append(account.UsersG, *user)
}
for id, group := range account.Groups {
group.ID = id
account.GroupsG = append(account.GroupsG, *group)
}
for id, route := range account.Routes {
route.ID = id
account.RoutesG = append(account.RoutesG, *route)
}
for id, ns := range account.NameServerGroups {
ns.ID = id
account.NameServerGroupsG = append(account.NameServerGroupsG, *ns)
}
err := s.db.Transaction(func(tx *gorm.DB) error { err := s.db.Transaction(func(tx *gorm.DB) error {
result := tx.Select(clause.Associations).Delete(account.Policies, "account_id = ?", account.Id) result := tx.Select(clause.Associations).Delete(account.Policies, "account_id = ?", account.Id)
@ -196,6 +170,58 @@ func (s *SqlStore) SaveAccount(account *Account) error {
return err return err
} }
// generateAccountSQLTypes generates the GORM compatible types for the account
func generateAccountSQLTypes(account *Account) {
for _, key := range account.SetupKeys {
account.SetupKeysG = append(account.SetupKeysG, *key)
}
for id, peer := range account.Peers {
peer.ID = id
account.PeersG = append(account.PeersG, *peer)
}
for id, user := range account.Users {
user.Id = id
for id, pat := range user.PATs {
pat.ID = id
user.PATsG = append(user.PATsG, *pat)
}
account.UsersG = append(account.UsersG, *user)
}
for id, group := range account.Groups {
group.ID = id
account.GroupsG = append(account.GroupsG, *group)
}
for id, route := range account.Routes {
route.ID = id
account.RoutesG = append(account.RoutesG, *route)
}
for id, ns := range account.NameServerGroups {
ns.ID = id
account.NameServerGroupsG = append(account.NameServerGroupsG, *ns)
}
}
// checkAccountDomainBeforeSave temporary method to troubleshoot an issue with domains getting blank
func (s *SqlStore) checkAccountDomainBeforeSave(accountID, newDomain string) {
var acc Account
var domain string
result := s.db.Model(&acc).Select("domain").Where(idQueryCondition, accountID).First(&domain)
if result.Error != nil {
if !errors.Is(result.Error, gorm.ErrRecordNotFound) {
log.Errorf("error when getting account %s from the store to check domain: %s", accountID, result.Error)
}
return
}
if domain != "" && newDomain == "" {
log.Warnf("saving an account with empty domain when there was a domain set. Previous domain %s, Account ID: %s, Trace: %s", domain, accountID, debug.Stack())
}
}
func (s *SqlStore) DeleteAccount(account *Account) error { func (s *SqlStore) DeleteAccount(account *Account) error {
start := time.Now() start := time.Now()
@ -237,7 +263,7 @@ func (s *SqlStore) SaveInstallationID(ID string) error {
func (s *SqlStore) GetInstallationID() string { func (s *SqlStore) GetInstallationID() string {
var installation installation var installation installation
if result := s.db.First(&installation, "id = ?", s.installationPK); result.Error != nil { if result := s.db.First(&installation, idQueryCondition, s.installationPK); result.Error != nil {
return "" return ""
} }
@ -345,7 +371,7 @@ func (s *SqlStore) GetTokenIDByHashedToken(hashedToken string) (string, error) {
func (s *SqlStore) GetUserByTokenID(tokenID string) (*User, error) { func (s *SqlStore) GetUserByTokenID(tokenID string) (*User, error) {
var token PersonalAccessToken var token PersonalAccessToken
result := s.db.First(&token, "id = ?", tokenID) result := s.db.First(&token, idQueryCondition, tokenID)
if result.Error != nil { if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) { if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, status.Errorf(status.NotFound, "account not found: index lookup failed") return nil, status.Errorf(status.NotFound, "account not found: index lookup failed")
@ -359,7 +385,7 @@ func (s *SqlStore) GetUserByTokenID(tokenID string) (*User, error) {
} }
var user User var user User
result = s.db.Preload("PATsG").First(&user, "id = ?", token.UserID) result = s.db.Preload("PATsG").First(&user, idQueryCondition, token.UserID)
if result.Error != nil { if result.Error != nil {
return nil, status.Errorf(status.NotFound, "account not found: index lookup failed") return nil, status.Errorf(status.NotFound, "account not found: index lookup failed")
} }
@ -394,7 +420,7 @@ func (s *SqlStore) GetAccount(accountID string) (*Account, error) {
result := s.db.Model(&account). result := s.db.Model(&account).
Preload("UsersG.PATsG"). // have to be specifies as this is nester reference Preload("UsersG.PATsG"). // have to be specifies as this is nester reference
Preload(clause.Associations). Preload(clause.Associations).
First(&account, "id = ?", accountID) First(&account, idQueryCondition, accountID)
if result.Error != nil { if result.Error != nil {
log.Errorf("error when getting account %s from the store: %s", accountID, result.Error) log.Errorf("error when getting account %s from the store: %s", accountID, result.Error)
if errors.Is(result.Error, gorm.ErrRecordNotFound) { if errors.Is(result.Error, gorm.ErrRecordNotFound) {
@ -458,7 +484,7 @@ func (s *SqlStore) GetAccount(accountID string) (*Account, error) {
func (s *SqlStore) GetAccountByUser(userID string) (*Account, error) { func (s *SqlStore) GetAccountByUser(userID string) (*Account, error) {
var user User var user User
result := s.db.Select("account_id").First(&user, "id = ?", userID) result := s.db.Select("account_id").First(&user, idQueryCondition, userID)
if result.Error != nil { if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) { if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, status.Errorf(status.NotFound, "account not found: index lookup failed") return nil, status.Errorf(status.NotFound, "account not found: index lookup failed")
@ -475,7 +501,7 @@ func (s *SqlStore) GetAccountByUser(userID string) (*Account, error) {
func (s *SqlStore) GetAccountByPeerID(peerID string) (*Account, error) { func (s *SqlStore) GetAccountByPeerID(peerID string) (*Account, error) {
var peer nbpeer.Peer var peer nbpeer.Peer
result := s.db.Select("account_id").First(&peer, "id = ?", peerID) result := s.db.Select("account_id").First(&peer, idQueryCondition, peerID)
if result.Error != nil { if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) { if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, status.Errorf(status.NotFound, "account not found: index lookup failed") return nil, status.Errorf(status.NotFound, "account not found: index lookup failed")
@ -528,7 +554,7 @@ func (s *SqlStore) GetAccountIDByPeerPubKey(peerKey string) (string, error) {
func (s *SqlStore) GetAccountIDByUserID(userID string) (string, error) { func (s *SqlStore) GetAccountIDByUserID(userID string) (string, error) {
var user User var user User
var accountID string var accountID string
result := s.db.Model(&user).Select("account_id").Where("id = ?", userID).First(&accountID) result := s.db.Model(&user).Select("account_id").Where(idQueryCondition, userID).First(&accountID)
if result.Error != nil { if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) { if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return "", status.Errorf(status.NotFound, "account not found: index lookup failed") return "", status.Errorf(status.NotFound, "account not found: index lookup failed")
@ -570,7 +596,7 @@ func (s *SqlStore) GetPeerByPeerPubKey(peerKey string) (*nbpeer.Peer, error) {
func (s *SqlStore) GetAccountSettings(accountID string) (*Settings, error) { func (s *SqlStore) GetAccountSettings(accountID string) (*Settings, error) {
var accountSettings AccountSettings var accountSettings AccountSettings
if err := s.db.Model(&Account{}).Where("id = ?", accountID).First(&accountSettings).Error; err != nil { if err := s.db.Model(&Account{}).Where(idQueryCondition, accountID).First(&accountSettings).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, status.Errorf(status.NotFound, "settings not found") return nil, status.Errorf(status.NotFound, "settings not found")
} }