github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/metricsmanager/metricsmanager.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // Package metricsmanager contains the implementation of an api endpoint 5 // for calling metrics functions in state. 6 package metricsmanager 7 8 import ( 9 "github.com/juju/errors" 10 "github.com/juju/loggo" 11 "github.com/juju/utils/clock" 12 "gopkg.in/juju/names.v2" 13 14 "github.com/juju/juju/apiserver/common" 15 "github.com/juju/juju/apiserver/facade" 16 "github.com/juju/juju/apiserver/metricsender" 17 "github.com/juju/juju/apiserver/params" 18 "github.com/juju/juju/state" 19 ) 20 21 var ( 22 logger = loggo.GetLogger("juju.apiserver.metricsmanager") 23 maxBatchesPerSend = metricsender.DefaultMaxBatchesPerSend() 24 25 sender = metricsender.DefaultMetricSender() 26 ) 27 28 func init() { 29 common.RegisterStandardFacade("MetricsManager", 1, newMetricsManagerAPI) 30 } 31 32 // MetricsManager defines the methods on the metricsmanager API end point. 33 type MetricsManager interface { 34 CleanupOldMetrics(arg params.Entities) (params.ErrorResults, error) 35 SendMetrics(args params.Entities) (params.ErrorResults, error) 36 } 37 38 // MetricsManagerAPI implements the metrics manager interface and is the concrete 39 // implementation of the api end point. 40 type MetricsManagerAPI struct { 41 state *state.State 42 43 accessEnviron common.GetAuthFunc 44 clock clock.Clock 45 } 46 47 var _ MetricsManager = (*MetricsManagerAPI)(nil) 48 49 // newMetricsManagerAPI wraps NewMetricsManagerAPI for RegisterStandardFacade. 50 func newMetricsManagerAPI( 51 st *state.State, 52 resources facade.Resources, 53 authorizer facade.Authorizer, 54 ) (*MetricsManagerAPI, error) { 55 return NewMetricsManagerAPI(st, resources, authorizer, clock.WallClock) 56 } 57 58 // NewMetricsManagerAPI creates a new API endpoint for calling metrics manager functions. 59 func NewMetricsManagerAPI( 60 st *state.State, 61 resources facade.Resources, 62 authorizer facade.Authorizer, 63 clock clock.Clock, 64 ) (*MetricsManagerAPI, error) { 65 if !(authorizer.AuthMachineAgent() && authorizer.AuthModelManager()) { 66 return nil, common.ErrPerm 67 } 68 69 // Allow access only to the current environment. 70 accessEnviron := func() (common.AuthFunc, error) { 71 return func(tag names.Tag) bool { 72 if tag == nil { 73 return false 74 } 75 return tag == st.ModelTag() 76 }, nil 77 } 78 79 return &MetricsManagerAPI{ 80 state: st, 81 accessEnviron: accessEnviron, 82 clock: clock, 83 }, nil 84 } 85 86 // CleanupOldMetrics removes old metrics from the collection. 87 // The single arg params is expected to contain and environment uuid. 88 // Even though the call will delete all metrics across environments 89 // it serves to validate that the connection has access to at least one environment. 90 func (api *MetricsManagerAPI) CleanupOldMetrics(args params.Entities) (params.ErrorResults, error) { 91 result := params.ErrorResults{ 92 Results: make([]params.ErrorResult, len(args.Entities)), 93 } 94 if len(args.Entities) == 0 { 95 return result, nil 96 } 97 canAccess, err := api.accessEnviron() 98 if err != nil { 99 return result, err 100 } 101 for i, arg := range args.Entities { 102 tag, err := names.ParseModelTag(arg.Tag) 103 if err != nil { 104 result.Results[i].Error = common.ServerError(common.ErrPerm) 105 continue 106 } 107 if !canAccess(tag) { 108 result.Results[i].Error = common.ServerError(common.ErrPerm) 109 continue 110 } 111 modelState := api.state 112 if tag != api.state.ModelTag() { 113 modelState, err = api.state.ForModel(tag) 114 if err != nil { 115 err = errors.Annotatef(err, "failed to access state for %s", tag) 116 result.Results[i].Error = common.ServerError(err) 117 continue 118 } 119 } 120 121 err = modelState.CleanupOldMetrics() 122 if err != nil { 123 err = errors.Annotatef(err, "failed to cleanup old metrics for %s", tag) 124 result.Results[i].Error = common.ServerError(err) 125 } 126 } 127 return result, nil 128 } 129 130 // SendMetrics will send any unsent metrics onto the metric collection service. 131 func (api *MetricsManagerAPI) SendMetrics(args params.Entities) (params.ErrorResults, error) { 132 result := params.ErrorResults{ 133 Results: make([]params.ErrorResult, len(args.Entities)), 134 } 135 if len(args.Entities) == 0 { 136 return result, nil 137 } 138 canAccess, err := api.accessEnviron() 139 if err != nil { 140 return result, err 141 } 142 for i, arg := range args.Entities { 143 tag, err := names.ParseModelTag(arg.Tag) 144 if err != nil { 145 result.Results[i].Error = common.ServerError(err) 146 continue 147 } 148 if !canAccess(tag) { 149 result.Results[i].Error = common.ServerError(common.ErrPerm) 150 continue 151 } 152 modelState := api.state 153 if tag != api.state.ModelTag() { 154 modelState, err = api.state.ForModel(tag) 155 if err != nil { 156 err = errors.Annotatef(err, "failed to access state for %s", tag) 157 result.Results[i].Error = common.ServerError(err) 158 continue 159 } 160 } 161 txVendorMetrics, err := transmitVendorMetrics(modelState) 162 if err != nil { 163 result.Results[i].Error = common.ServerError(err) 164 continue 165 } 166 err = metricsender.SendMetrics(modelState, sender, api.clock, maxBatchesPerSend, txVendorMetrics) 167 if err != nil { 168 err = errors.Annotatef(err, "failed to send metrics for %s", tag) 169 logger.Warningf("%v", err) 170 result.Results[i].Error = common.ServerError(err) 171 continue 172 } 173 } 174 return result, nil 175 } 176 177 func transmitVendorMetrics(st *state.State) (bool, error) { 178 cfg, err := st.ModelConfig() 179 if err != nil { 180 return false, errors.Annotatef(err, "failed to get model config for %s", st.ModelTag()) 181 } 182 return cfg.TransmitVendorMetrics(), nil 183 }