github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/auditconfigupdater/worker.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package auditconfigupdater 5 6 import ( 7 "sync" 8 9 "github.com/juju/errors" 10 "gopkg.in/juju/worker.v1" 11 "gopkg.in/juju/worker.v1/catacomb" 12 13 "github.com/juju/juju/controller" 14 "github.com/juju/juju/core/auditlog" 15 "github.com/juju/juju/state" 16 ) 17 18 // ConfigSource lets us get notifications of changes to controller 19 // configuration, and then get the changed config. (Primary 20 // implementation is State.) 21 type ConfigSource interface { 22 WatchControllerConfig() state.NotifyWatcher 23 ControllerConfig() (controller.Config, error) 24 } 25 26 // AuditLogFactory is a function that will return an audit log given 27 // config. 28 type AuditLogFactory func(auditlog.Config) auditlog.AuditLog 29 30 // New returns a worker that will keep an up-to-date audit log config. 31 func New(source ConfigSource, initial auditlog.Config, logFactory AuditLogFactory) (worker.Worker, error) { 32 u := &updater{ 33 source: source, 34 current: initial, 35 logFactory: logFactory, 36 } 37 err := catacomb.Invoke(catacomb.Plan{ 38 Site: &u.catacomb, 39 Work: u.loop, 40 }) 41 if err != nil { 42 return nil, errors.Trace(err) 43 } 44 return u, nil 45 } 46 47 type updater struct { 48 mu sync.Mutex 49 catacomb catacomb.Catacomb 50 source ConfigSource 51 current auditlog.Config 52 logFactory AuditLogFactory 53 } 54 55 // Kill is part of the worker.Worker interface. 56 func (u *updater) Kill() { 57 u.catacomb.Kill(nil) 58 } 59 60 // Wait is part of the worker.Worker interface. 61 func (u *updater) Wait() error { 62 return u.catacomb.Wait() 63 } 64 65 func (u *updater) loop() error { 66 watcher := u.source.WatchControllerConfig() 67 if err := u.catacomb.Add(watcher); err != nil { 68 return errors.Trace(err) 69 } 70 for { 71 select { 72 case <-u.catacomb.Dying(): 73 return u.catacomb.ErrDying() 74 case _, ok := <-watcher.Changes(): 75 if !ok { 76 return errors.Errorf("watcher channel closed") 77 } 78 newConfig, err := u.newConfig() 79 if err != nil { 80 return errors.Annotatef(err, "getting new config") 81 } 82 u.update(newConfig) 83 } 84 } 85 } 86 87 func (u *updater) newConfig() (auditlog.Config, error) { 88 cfg, err := u.source.ControllerConfig() 89 if err != nil { 90 return auditlog.Config{}, errors.Trace(err) 91 } 92 result := auditlog.Config{ 93 Enabled: cfg.AuditingEnabled(), 94 CaptureAPIArgs: cfg.AuditLogCaptureArgs(), 95 MaxSizeMB: cfg.AuditLogMaxSizeMB(), 96 MaxBackups: cfg.AuditLogMaxBackups(), 97 ExcludeMethods: cfg.AuditLogExcludeMethods(), 98 } 99 if result.Enabled && u.current.Target == nil { 100 result.Target = u.logFactory(result) 101 } else { 102 // Keep the existing target to avoid file handle leaks from 103 // disabling and enabling auditing - we'll still stop logging 104 // because enabled is false. 105 result.Target = u.current.Target 106 } 107 return result, nil 108 } 109 110 func (u *updater) update(newConfig auditlog.Config) { 111 u.mu.Lock() 112 defer u.mu.Unlock() 113 u.current = newConfig 114 } 115 116 // CurrentConfig returns the updater's up-to-date audit config. 117 func (u *updater) CurrentConfig() auditlog.Config { 118 u.mu.Lock() 119 defer u.mu.Unlock() 120 return u.current 121 }