mirror of
https://blitiri.com.ar/repos/chasquid
synced 2025-12-17 14:37:02 +00:00
Log how many things were loaded for each domain
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.
This commit is contained in:
23
chasquid.go
23
chasquid.go
@@ -282,30 +282,31 @@ func loadCert(name, dir string, s *smtpsrv.Server) {
|
|||||||
|
|
||||||
// Helper to load a single domain configuration into the server.
|
// Helper to load a single domain configuration into the server.
|
||||||
func loadDomain(name, dir string, s *smtpsrv.Server) {
|
func loadDomain(name, dir string, s *smtpsrv.Server) {
|
||||||
log.Infof(" %s", name)
|
|
||||||
s.AddDomain(name)
|
s.AddDomain(name)
|
||||||
|
|
||||||
err := s.AddUserDB(name, dir+"/users")
|
nu, err := s.AddUserDB(name, dir+"/users")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If there is an error loading users, fail hard to make sure this is
|
// If there is an error loading users, fail hard to make sure this is
|
||||||
// noticed and fixed as soon as it happens.
|
// 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 err != nil {
|
||||||
// If there's an error loading aliases, fail hard to make sure this is
|
// If there's an error loading aliases, fail hard to make sure this is
|
||||||
// noticed and fixed as soon as it happens.
|
// 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 {
|
if err != nil {
|
||||||
// DKIM errors are fatal because if the user set DKIM up, then we
|
// 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
|
// don't want it to be failing silently, as that could cause
|
||||||
// deliverability issues.
|
// 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) {
|
func loadDovecot(s *smtpsrv.Server, userdb, client string) {
|
||||||
@@ -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")
|
glob := path.Clean(dir + "/dkim:*.pem")
|
||||||
pems, err := filepath.Glob(glob)
|
pems, err := filepath.Glob(glob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pem := range pems {
|
for _, pem := range pems {
|
||||||
@@ -332,10 +333,10 @@ func loadDKIM(domain, dir string, s *smtpsrv.Server) error {
|
|||||||
|
|
||||||
err = s.AddDKIMSigner(domain, selector, pem)
|
err = s.AddDKIMSigner(domain, selector, pem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return len(pems), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a directory, which must have at least some entries.
|
// Read a directory, which must have at least some entries.
|
||||||
|
|||||||
@@ -156,12 +156,12 @@ func checkUserDB() {
|
|||||||
Fatalf("Error: file %q does not exist", path)
|
Fatalf("Error: file %q does not exist", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := userdb.Load(path)
|
udb, err := userdb.Load(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Error loading database: %v", err)
|
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]
|
// chasquid-util user-add <user@domain> [--password=<password>] [--receive_only]
|
||||||
|
|||||||
@@ -1,16 +1,25 @@
|
|||||||
# Tests for user management commands.
|
# 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 = ./chasquid-util -C=.config user-add user@domain --password=passwd
|
||||||
c <- Added user
|
c <- Added user
|
||||||
c wait 0
|
c wait 0
|
||||||
|
|
||||||
c = ./chasquid-util -C=.config check-userdb domain
|
c = ./chasquid-util -C=.config check-userdb domain
|
||||||
c <- Database loaded
|
c <- Database loaded (1 users)
|
||||||
c wait 0
|
c wait 0
|
||||||
|
|
||||||
c = ./chasquid-util -C=.config user-add receive@domain --receive_only
|
c = ./chasquid-util -C=.config user-add receive@domain --receive_only
|
||||||
c <- Added user
|
c <- Added user
|
||||||
c wait 0
|
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 \
|
c = ./chasquid-util -C=.config user-add xxx@domain \
|
||||||
--password=passwd --receive_only
|
--password=passwd --receive_only
|
||||||
c <- Cannot specify both --receive_only and --password
|
c <- Cannot specify both --receive_only and --password
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ func (v *Resolver) AddDomain(domain string) {
|
|||||||
// AddAliasesFile to the resolver. The file will be parsed, and an error
|
// 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
|
// returned if it does not parse correctly. Note that the file not existing
|
||||||
// does NOT result in an error.
|
// 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.
|
// 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
|
// Even if the file does not exist now, it may later. This makes it be
|
||||||
// consider when doing Reload.
|
// consider when doing Reload.
|
||||||
@@ -360,10 +360,10 @@ func (v *Resolver) AddAliasesFile(domain, path string) error {
|
|||||||
|
|
||||||
aliases, err := v.parseFile(domain, path)
|
aliases, err := v.parseFile(domain, path)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the aliases to the resolver, overriding any previous values.
|
// Add the aliases to the resolver, overriding any previous values.
|
||||||
@@ -373,7 +373,7 @@ func (v *Resolver) AddAliasesFile(domain, path string) error {
|
|||||||
}
|
}
|
||||||
v.mu.Unlock()
|
v.mu.Unlock()
|
||||||
|
|
||||||
return nil
|
return len(aliases), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddAliasForTesting adds an alias to the resolver, for testing purposes.
|
// AddAliasForTesting adds an alias to the resolver, for testing purposes.
|
||||||
|
|||||||
@@ -437,7 +437,7 @@ func TestAddFile(t *testing.T) {
|
|||||||
defer os.Remove(fname)
|
defer os.Remove(fname)
|
||||||
|
|
||||||
resolver := NewResolver(allUsersExist)
|
resolver := NewResolver(allUsersExist)
|
||||||
err := resolver.AddAliasesFile("dom", fname)
|
_, err := resolver.AddAliasesFile("dom", fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error adding file: %v", err)
|
t.Fatalf("error adding file: %v", err)
|
||||||
}
|
}
|
||||||
@@ -491,11 +491,15 @@ func TestRichFile(t *testing.T) {
|
|||||||
resolver := NewResolver(allUsersExist)
|
resolver := NewResolver(allUsersExist)
|
||||||
resolver.DropChars = "."
|
resolver.DropChars = "."
|
||||||
resolver.SuffixSep = "+"
|
resolver.SuffixSep = "+"
|
||||||
err := resolver.AddAliasesFile("dom", fname)
|
n, err := resolver.AddAliasesFile("dom", fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to add file: %v", err)
|
t.Fatalf("failed to add file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n != 11 {
|
||||||
|
t.Fatalf("expected 11 aliases, got %d", n)
|
||||||
|
}
|
||||||
|
|
||||||
cases := Cases{
|
cases := Cases{
|
||||||
{"a@dom", []Recipient{{"b@dom", EMAIL}}, nil},
|
{"a@dom", []Recipient{{"b@dom", EMAIL}}, nil},
|
||||||
{"c@dom", []Recipient{{"d@e", EMAIL}, {"f@dom", EMAIL}}, nil},
|
{"c@dom", []Recipient{{"d@e", EMAIL}, {"f@dom", EMAIL}}, nil},
|
||||||
@@ -539,7 +543,7 @@ func TestManyFiles(t *testing.T) {
|
|||||||
|
|
||||||
resolver := NewResolver(allUsersExist)
|
resolver := NewResolver(allUsersExist)
|
||||||
for domain, fname := range files {
|
for domain, fname := range files {
|
||||||
err := resolver.AddAliasesFile(domain, fname)
|
_, err := resolver.AddAliasesFile(domain, fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to add file: %v", err)
|
t.Fatalf("failed to add file: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,16 +133,16 @@ func (s *Server) AddDomain(d string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddUserDB adds a userdb file as backend for the domain.
|
// 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
|
// Load the userdb, and register it unconditionally (so reload works even
|
||||||
// if there are errors right now).
|
// if there are errors right now).
|
||||||
udb, err := userdb.Load(f)
|
udb, err := userdb.Load(f)
|
||||||
s.authr.Register(domain, auth.WrapNoErrorBackend(udb))
|
s.authr.Register(domain, auth.WrapNoErrorBackend(udb))
|
||||||
return err
|
return udb.Len(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddAliasesFile adds an aliases file for the given domain.
|
// 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)
|
return s.aliasesR.AddAliasesFile(domain, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -207,6 +207,13 @@ func (db *DB) Exists(name string) bool {
|
|||||||
return present
|
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
|
// Encryption schemes
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user