github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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 "gopkg.in/juju/names.v2" 9 10 "github.com/juju/juju/apiserver/common" 11 "github.com/juju/juju/apiserver/facade" 12 "github.com/juju/juju/apiserver/params" 13 "github.com/juju/juju/core/cache" 14 "github.com/juju/juju/environs/config" 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 // NewLoggerAPI creates a new server-side logger API end point. 38 func NewLoggerAPI(ctx facade.Context) (*LoggerAPI, error) { 39 st := ctx.State() 40 resources := ctx.Resources() 41 authorizer := ctx.Auth() 42 43 if !authorizer.AuthMachineAgent() && !authorizer.AuthUnitAgent() && !authorizer.AuthApplicationAgent() { 44 return nil, common.ErrPerm 45 } 46 m, err := ctx.Controller().Model(st.ModelUUID()) 47 if err != nil { 48 return nil, err 49 } 50 51 return &LoggerAPI{ 52 controller: ctx.Controller(), 53 model: m, 54 resources: resources, 55 authorizer: authorizer, 56 }, nil 57 } 58 59 // WatchLoggingConfig starts a watcher to track changes to the logging config 60 // for the agents specified.. Unfortunately the current infrastruture makes 61 // watching parts of the config non-trivial, so currently any change to the 62 // config will cause the watcher to notify the client. 63 func (api *LoggerAPI) WatchLoggingConfig(arg params.Entities) params.NotifyWatchResults { 64 result := make([]params.NotifyWatchResult, len(arg.Entities)) 65 for i, entity := range arg.Entities { 66 tag, err := names.ParseTag(entity.Tag) 67 if err != nil { 68 result[i].Error = common.ServerError(err) 69 continue 70 } 71 err = common.ErrPerm 72 if api.authorizer.AuthOwner(tag) { 73 watch := api.model.WatchConfig("logging-config") 74 // Consume the initial event. Technically, API calls to Watch 75 // 'transmit' the initial event in the Watch response. But 76 // NotifyWatchers have no state to transmit. 77 if _, ok := <-watch.Changes(); ok { 78 result[i].NotifyWatcherId = api.resources.Register(watch) 79 err = nil 80 } else { 81 err = errors.New("programming error: channel should not be closed") 82 } 83 } 84 result[i].Error = common.ServerError(err) 85 } 86 return params.NotifyWatchResults{Results: result} 87 } 88 89 // LoggingConfig reports the logging configuration for the agents specified. 90 func (api *LoggerAPI) LoggingConfig(arg params.Entities) params.StringResults { 91 if len(arg.Entities) == 0 { 92 return params.StringResults{} 93 } 94 results := make([]params.StringResult, len(arg.Entities)) 95 // TODO: ensure that the cache model can return a proper config object. 96 config, configErr := config.New(config.NoDefaults, api.model.Config()) 97 for i, entity := range arg.Entities { 98 tag, err := names.ParseTag(entity.Tag) 99 if err != nil { 100 results[i].Error = common.ServerError(err) 101 continue 102 } 103 err = common.ErrPerm 104 if api.authorizer.AuthOwner(tag) { 105 if configErr == nil { 106 results[i].Result = config.LoggingConfig() 107 err = nil 108 } else { 109 err = configErr 110 } 111 } 112 results[i].Error = common.ServerError(err) 113 } 114 return params.StringResults{Results: results} 115 }