github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/agent/logger/logger.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package logger
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names/v5"
     9  
    10  	apiservererrors "github.com/juju/juju/apiserver/errors"
    11  	"github.com/juju/juju/apiserver/facade"
    12  	"github.com/juju/juju/core/cache"
    13  	"github.com/juju/juju/environs/config"
    14  	"github.com/juju/juju/rpc/params"
    15  )
    16  
    17  // Logger defines the methods on the logger API end point.  Unfortunately, the
    18  // api infrastructure doesn't allow interfaces to be used as an actual
    19  // endpoint because our rpc mechanism panics.  However, I still feel that this
    20  // provides a useful documentation purpose.
    21  type Logger interface {
    22  	WatchLoggingConfig(args params.Entities) params.NotifyWatchResults
    23  	LoggingConfig(args params.Entities) params.StringResults
    24  }
    25  
    26  // LoggerAPI implements the Logger interface and is the concrete
    27  // implementation of the api end point.
    28  type LoggerAPI struct {
    29  	controller *cache.Controller
    30  	model      *cache.Model
    31  	resources  facade.Resources
    32  	authorizer facade.Authorizer
    33  }
    34  
    35  var _ Logger = (*LoggerAPI)(nil)
    36  
    37  // WatchLoggingConfig starts a watcher to track changes to the logging config
    38  // for the agents specified..  Unfortunately the current infrastructure makes
    39  // watching parts of the config non-trivial, so currently any change to the
    40  // config will cause the watcher to notify the client.
    41  func (api *LoggerAPI) WatchLoggingConfig(arg params.Entities) params.NotifyWatchResults {
    42  	result := make([]params.NotifyWatchResult, len(arg.Entities))
    43  	for i, entity := range arg.Entities {
    44  		tag, err := names.ParseTag(entity.Tag)
    45  		if err != nil {
    46  			result[i].Error = apiservererrors.ServerError(err)
    47  			continue
    48  		}
    49  		err = apiservererrors.ErrPerm
    50  		if api.authorizer.AuthOwner(tag) {
    51  			watch := api.model.WatchConfig("logging-config")
    52  			// Consume the initial event. Technically, API calls to Watch
    53  			// 'transmit' the initial event in the Watch response. But
    54  			// NotifyWatchers have no state to transmit.
    55  			if _, ok := <-watch.Changes(); ok {
    56  				result[i].NotifyWatcherId = api.resources.Register(watch)
    57  				err = nil
    58  			} else {
    59  				err = errors.New("programming error: channel should not be closed")
    60  			}
    61  		}
    62  		result[i].Error = apiservererrors.ServerError(err)
    63  	}
    64  	return params.NotifyWatchResults{Results: result}
    65  }
    66  
    67  // LoggingConfig reports the logging configuration for the agents specified.
    68  func (api *LoggerAPI) LoggingConfig(arg params.Entities) params.StringResults {
    69  	if len(arg.Entities) == 0 {
    70  		return params.StringResults{}
    71  	}
    72  	results := make([]params.StringResult, len(arg.Entities))
    73  	// TODO: ensure that the cache model can return a proper config object.
    74  	config, configErr := config.New(config.NoDefaults, api.model.Config())
    75  	for i, entity := range arg.Entities {
    76  		tag, err := names.ParseTag(entity.Tag)
    77  		if err != nil {
    78  			results[i].Error = apiservererrors.ServerError(err)
    79  			continue
    80  		}
    81  		err = apiservererrors.ErrPerm
    82  		if api.authorizer.AuthOwner(tag) {
    83  			if configErr == nil {
    84  				results[i].Result = config.LoggingConfig()
    85  				err = nil
    86  			} else {
    87  				err = configErr
    88  			}
    89  		}
    90  		results[i].Error = apiservererrors.ServerError(err)
    91  	}
    92  	return params.StringResults{Results: results}
    93  }