~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/apiserver/metricsdebug/metricsdebug.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

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