github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/metricsdebug/metricsdebug.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // Package metricsdebug contains the implementation of an api endpoint 5 // for metrics debug functionality. 6 package metricsdebug 7 8 import ( 9 "github.com/juju/errors" 10 "github.com/juju/names" 11 12 "github.com/juju/juju/apiserver/common" 13 "github.com/juju/juju/apiserver/params" 14 "github.com/juju/juju/state" 15 ) 16 17 func init() { 18 common.RegisterStandardFacade("MetricsDebug", 1, NewMetricsDebugAPI) 19 } 20 21 type metricsDebug interface { 22 // MetricBatchesForUnit returns metric batches for the given unit. 23 MetricBatchesForUnit(unit string) ([]state.MetricBatch, error) 24 25 // MetricBatchesForService returns metric batches for the given service. 26 MetricBatchesForService(service string) ([]state.MetricBatch, error) 27 28 // Unit returns the unit based on its name. 29 Unit(string) (*state.Unit, error) 30 31 // Service returns the service based on its name. 32 Service(string) (*state.Service, error) 33 } 34 35 // MetricsDebug defines the methods on the metricsdebug API end point. 36 type MetricsDebug interface { 37 // GetMetrics returns all metrics stored by the state server. 38 GetMetrics(arg params.Entities) (params.MetricResults, error) 39 40 // SetMeterStatus will set the meter status on the given entity tag. 41 SetMeterStatus(params.MeterStatusParams) (params.ErrorResults, error) 42 } 43 44 // MetricsDebugAPI implements the metricsdebug interface and is the concrete 45 // implementation of the api end point. 46 type MetricsDebugAPI struct { 47 state metricsDebug 48 } 49 50 var _ MetricsDebug = (*MetricsDebugAPI)(nil) 51 52 // NewMetricsDebugAPI creates a new API endpoint for calling metrics debug functions. 53 func NewMetricsDebugAPI( 54 st *state.State, 55 resources *common.Resources, 56 authorizer common.Authorizer, 57 ) (*MetricsDebugAPI, error) { 58 if !authorizer.AuthClient() { 59 return nil, common.ErrPerm 60 } 61 62 return &MetricsDebugAPI{ 63 state: st, 64 }, nil 65 } 66 67 // GetMetrics returns all metrics stored by the state server. 68 func (api *MetricsDebugAPI) GetMetrics(args params.Entities) (params.MetricResults, error) { 69 results := params.MetricResults{ 70 Results: make([]params.EntityMetrics, len(args.Entities)), 71 } 72 if len(args.Entities) == 0 { 73 return results, nil 74 } 75 for i, arg := range args.Entities { 76 tag, err := names.ParseTag(arg.Tag) 77 if err != nil { 78 results.Results[i].Error = common.ServerError(err) 79 continue 80 } 81 var batches []state.MetricBatch 82 switch tag.Kind() { 83 case names.UnitTagKind: 84 batches, err = api.state.MetricBatchesForUnit(tag.Id()) 85 if err != nil { 86 err = errors.Annotate(err, "failed to get metrics") 87 results.Results[i].Error = common.ServerError(err) 88 continue 89 } 90 case names.ServiceTagKind: 91 batches, err = api.state.MetricBatchesForService(tag.Id()) 92 if err != nil { 93 err = errors.Annotate(err, "failed to get metrics") 94 results.Results[i].Error = common.ServerError(err) 95 continue 96 } 97 default: 98 err := errors.Errorf("invalid tag %v", arg.Tag) 99 results.Results[i].Error = common.ServerError(err) 100 } 101 metricCount := 0 102 for _, b := range batches { 103 metricCount += len(b.Metrics()) 104 } 105 metrics := make([]params.MetricResult, metricCount) 106 ix := 0 107 for _, mb := range batches { 108 for _, m := range mb.Metrics() { 109 metrics[ix] = params.MetricResult{ 110 Key: m.Key, 111 Value: m.Value, 112 Time: m.Time, 113 } 114 ix++ 115 } 116 results.Results[i].Metrics = metrics 117 } 118 } 119 return results, nil 120 } 121 122 // SetMeterStatus sets meter statuses for entities. 123 func (api *MetricsDebugAPI) SetMeterStatus(args params.MeterStatusParams) (params.ErrorResults, error) { 124 results := params.ErrorResults{ 125 Results: make([]params.ErrorResult, len(args.Statuses)), 126 } 127 for i, arg := range args.Statuses { 128 tag, err := names.ParseTag(arg.Tag) 129 if err != nil { 130 results.Results[i].Error = common.ServerError(err) 131 continue 132 } 133 err = api.setEntityMeterStatus(tag, state.MeterStatus{ 134 Code: state.MeterStatusFromString(arg.Code), 135 Info: arg.Info, 136 }) 137 if err != nil { 138 results.Results[i].Error = common.ServerError(err) 139 continue 140 } 141 } 142 return results, nil 143 } 144 145 func (api *MetricsDebugAPI) setEntityMeterStatus(entity names.Tag, status state.MeterStatus) error { 146 switch entity := entity.(type) { 147 case names.UnitTag: 148 unit, err := api.state.Unit(entity.Id()) 149 if err != nil { 150 return errors.Trace(err) 151 } 152 chURL, found := unit.CharmURL() 153 if !found { 154 return errors.New("no charm url") 155 } 156 if chURL.Schema != "local" { 157 return errors.New("not a local charm") 158 } 159 err = unit.SetMeterStatus(status.Code.String(), status.Info) 160 if err != nil { 161 return errors.Trace(err) 162 } 163 case names.ServiceTag: 164 service, err := api.state.Service(entity.Id()) 165 if err != nil { 166 return errors.Trace(err) 167 } 168 chURL, _ := service.CharmURL() 169 if chURL.Schema != "local" { 170 return errors.New("not a local charm") 171 } 172 units, err := service.AllUnits() 173 if err != nil { 174 return errors.Trace(err) 175 } 176 for _, unit := range units { 177 err := unit.SetMeterStatus(status.Code.String(), status.Info) 178 if err != nil { 179 return errors.Trace(err) 180 } 181 } 182 default: 183 return errors.Errorf("expected service or unit tag, got %T", entity) 184 } 185 return nil 186 }