Skip to content

Commit

Permalink
Log how many things were loaded for each domain
Browse files Browse the repository at this point in the history
This patch makes chasquid log how many users, aliases and DKIM keys were
loaded for each domain.

This makes it easier to confirm changes, and troubleshoot problems
related to these per-domain configuration files.
  • Loading branch information
albertito committed May 10, 2024
1 parent e6a9410 commit aae0367
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 24 deletions.
23 changes: 12 additions & 11 deletions chasquid.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,30 +282,31 @@ func loadCert(name, dir string, s *smtpsrv.Server) {

// Helper to load a single domain configuration into the server.
func loadDomain(name, dir string, s *smtpsrv.Server) {
log.Infof(" %s", name)
s.AddDomain(name)

err := s.AddUserDB(name, dir+"/users")
nu, err := s.AddUserDB(name, dir+"/users")
if err != nil {
// If there is an error loading users, fail hard to make sure this is
// noticed and fixed as soon as it happens.
log.Fatalf(" users file error: %v", err)
log.Fatalf(" %s: users file error: %v", name, err)
}

err = s.AddAliasesFile(name, dir+"/aliases")
na, err := s.AddAliasesFile(name, dir+"/aliases")
if err != nil {
// If there's an error loading aliases, fail hard to make sure this is
// noticed and fixed as soon as it happens.
log.Fatalf(" aliases file error: %v", err)
log.Fatalf(" %s: aliases file error: %v", name, err)
}

err = loadDKIM(name, dir, s)
nd, err := loadDKIM(name, dir, s)
if err != nil {
// DKIM errors are fatal because if the user set DKIM up, then we
// don't want it to be failing silently, as that could cause
// deliverability issues.
log.Fatalf(" DKIM loading error: %v", err)
log.Fatalf(" %s: DKIM loading error: %v", name, err)
}

log.Infof(" %s (%d users, %d aliases, %d DKIM keys)", name, nu, na, nd)
}

func loadDovecot(s *smtpsrv.Server, userdb, client string) {
Expand All @@ -318,11 +319,11 @@ func loadDovecot(s *smtpsrv.Server, userdb, client string) {
}
}

func loadDKIM(domain, dir string, s *smtpsrv.Server) error {
func loadDKIM(domain, dir string, s *smtpsrv.Server) (int, error) {
glob := path.Clean(dir + "/dkim:*.pem")
pems, err := filepath.Glob(glob)
if err != nil {
return err
return 0, err
}

for _, pem := range pems {
Expand All @@ -332,10 +333,10 @@ func loadDKIM(domain, dir string, s *smtpsrv.Server) error {

err = s.AddDKIMSigner(domain, selector, pem)
if err != nil {
return err
return 0, err
}
}
return nil
return len(pems), nil
}

// Read a directory, which must have at least some entries.
Expand Down
4 changes: 2 additions & 2 deletions cmd/chasquid-util/chasquid-util.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,12 @@ func checkUserDB() {
Fatalf("Error: file %q does not exist", path)
}

_, err := userdb.Load(path)
udb, err := userdb.Load(path)
if err != nil {
Fatalf("Error loading database: %v", err)
}

fmt.Println("Database loaded")
fmt.Printf("Database loaded (%d users)\n", udb.Len())
}

// chasquid-util user-add <user@domain> [--password=<password>] [--receive_only]
Expand Down
11 changes: 10 additions & 1 deletion cmd/chasquid-util/test_users.cmy
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
# Tests for user management commands.
# Start with a clean slate by removing the database, which could have been
# manipulated by previous tests.
c = rm -f .config/domains/domain/users
c wait 0

c = ./chasquid-util -C=.config user-add user@domain --password=passwd
c <- Added user
c wait 0

c = ./chasquid-util -C=.config check-userdb domain
c <- Database loaded
c <- Database loaded (1 users)
c wait 0

c = ./chasquid-util -C=.config user-add receive@domain --receive_only
c <- Added user
c wait 0

c = ./chasquid-util -C=.config check-userdb domain
c <- Database loaded (2 users)
c wait 0

c = ./chasquid-util -C=.config user-add xxx@domain \
--password=passwd --receive_only
c <- Cannot specify both --receive_only and --password
Expand Down
8 changes: 4 additions & 4 deletions internal/aliases/aliases.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ func (v *Resolver) AddDomain(domain string) {
// AddAliasesFile to the resolver. The file will be parsed, and an error
// returned if it does not parse correctly. Note that the file not existing
// does NOT result in an error.
func (v *Resolver) AddAliasesFile(domain, path string) error {
func (v *Resolver) AddAliasesFile(domain, path string) (int, error) {
// We unconditionally add the domain and file on our list.
// Even if the file does not exist now, it may later. This makes it be
// consider when doing Reload.
Expand All @@ -360,10 +360,10 @@ func (v *Resolver) AddAliasesFile(domain, path string) error {

aliases, err := v.parseFile(domain, path)
if os.IsNotExist(err) {
return nil
return 0, nil
}
if err != nil {
return err
return 0, err
}

// Add the aliases to the resolver, overriding any previous values.
Expand All @@ -373,7 +373,7 @@ func (v *Resolver) AddAliasesFile(domain, path string) error {
}
v.mu.Unlock()

return nil
return len(aliases), nil
}

// AddAliasForTesting adds an alias to the resolver, for testing purposes.
Expand Down
10 changes: 7 additions & 3 deletions internal/aliases/aliases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ func TestAddFile(t *testing.T) {
defer os.Remove(fname)

resolver := NewResolver(allUsersExist)
err := resolver.AddAliasesFile("dom", fname)
_, err := resolver.AddAliasesFile("dom", fname)
if err != nil {
t.Fatalf("error adding file: %v", err)
}
Expand Down Expand Up @@ -491,11 +491,15 @@ func TestRichFile(t *testing.T) {
resolver := NewResolver(allUsersExist)
resolver.DropChars = "."
resolver.SuffixSep = "+"
err := resolver.AddAliasesFile("dom", fname)
n, err := resolver.AddAliasesFile("dom", fname)
if err != nil {
t.Fatalf("failed to add file: %v", err)
}

if n != 11 {
t.Fatalf("expected 11 aliases, got %d", n)
}

cases := Cases{
{"a@dom", []Recipient{{"b@dom", EMAIL}}, nil},
{"c@dom", []Recipient{{"d@e", EMAIL}, {"f@dom", EMAIL}}, nil},
Expand Down Expand Up @@ -539,7 +543,7 @@ func TestManyFiles(t *testing.T) {

resolver := NewResolver(allUsersExist)
for domain, fname := range files {
err := resolver.AddAliasesFile(domain, fname)
_, err := resolver.AddAliasesFile(domain, fname)
if err != nil {
t.Fatalf("failed to add file: %v", err)
}
Expand Down
6 changes: 3 additions & 3 deletions internal/smtpsrv/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,16 @@ func (s *Server) AddDomain(d string) {
}

// AddUserDB adds a userdb file as backend for the domain.
func (s *Server) AddUserDB(domain, f string) error {
func (s *Server) AddUserDB(domain, f string) (int, error) {
// Load the userdb, and register it unconditionally (so reload works even
// if there are errors right now).
udb, err := userdb.Load(f)
s.authr.Register(domain, auth.WrapNoErrorBackend(udb))
return err
return udb.Len(), err
}

// AddAliasesFile adds an aliases file for the given domain.
func (s *Server) AddAliasesFile(domain, f string) error {
func (s *Server) AddAliasesFile(domain, f string) (int, error) {
return s.aliasesR.AddAliasesFile(domain, f)
}

Expand Down
7 changes: 7 additions & 0 deletions internal/userdb/userdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,13 @@ func (db *DB) Exists(name string) bool {
return present
}

// Len returns the number of users in the database.
func (db *DB) Len() int {
db.mu.Lock()
defer db.mu.Unlock()
return len(db.db.Users)
}

///////////////////////////////////////////////////////////
// Encryption schemes
//
Expand Down

0 comments on commit aae0367

Please sign in to comment.