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  }