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 }