Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

state/meterstatus: Wired up meter status with metrics manager status #1677

Merged
merged 6 commits into from Mar 24, 2015
4 changes: 2 additions & 2 deletions api/uniter/unit_test.go
Expand Up @@ -769,8 +769,8 @@ func (s *unitSuite) TestWatchMeterStatus(c *gc.C) {
err := mm.IncrementConsecutiveErrors()
c.Assert(err, jc.ErrorIsNil)
}
code, _ := mm.MeterStatus()
c.Assert(code, gc.Equals, state.MeterAmber) // Confirm meter status has changed
status := mm.MeterStatus()
c.Assert(status.Code, gc.Equals, state.MeterAmber) // Confirm meter status has changed
wc.AssertOneChange()

statetesting.AssertStop(c, w)
Expand Down
30 changes: 12 additions & 18 deletions apiserver/metricsender/sender_test.go
Expand Up @@ -190,19 +190,17 @@ func (s *SenderSuite) TestMeterStatus(c *gc.C) {

_ = s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false})

status, info, err := s.unit.GetMeterStatus()
status, err := s.unit.GetMeterStatus()
c.Assert(err, jc.ErrorIsNil)
c.Assert(status, gc.Equals, "NOT SET")
c.Assert(info, gc.Equals, "")
c.Assert(status.Code, gc.Equals, state.MeterNotSet)

var sender metricsender.DefaultSender
err = metricsender.SendMetrics(s.State, &sender, 10)
c.Assert(err, jc.ErrorIsNil)

status, info, err = s.unit.GetMeterStatus()
status, err = s.unit.GetMeterStatus()
c.Assert(err, jc.ErrorIsNil)
c.Assert(status, gc.Equals, "GREEN")
c.Assert(info, gc.Equals, "")
c.Assert(status.Code, gc.Equals, state.MeterGreen)
}

// TestMeterStatusInvalid checks that the metric sender deals with invalid
Expand Down Expand Up @@ -236,30 +234,26 @@ func (s *SenderSuite) TestMeterStatusInvalid(c *gc.C) {
_ = s.Factory.MakeMetric(c, &factory.MetricParams{Unit: unit3, Sent: false})

for _, unit := range []*state.Unit{unit1, unit2, unit3} {
status, info, err := unit.GetMeterStatus()
status, err := unit.GetMeterStatus()
c.Assert(err, jc.ErrorIsNil)
c.Assert(status, gc.Equals, "NOT SET")
c.Assert(info, gc.Equals, "")
c.Assert(status.Code, gc.Equals, state.MeterNotSet)
}

var sender metricsender.DefaultSender
err := metricsender.SendMetrics(s.State, &sender, 10)
c.Assert(err, jc.ErrorIsNil)

status, info, err := unit1.GetMeterStatus()
status, err := unit1.GetMeterStatus()
c.Assert(err, jc.ErrorIsNil)
c.Assert(status, gc.Equals, "GREEN")
c.Assert(info, gc.Equals, "")
c.Assert(status.Code, gc.Equals, state.MeterGreen)

status, info, err = unit2.GetMeterStatus()
status, err = unit2.GetMeterStatus()
c.Assert(err, jc.ErrorIsNil)
c.Assert(status, gc.Equals, "NOT SET")
c.Assert(info, gc.Equals, "")
c.Assert(status.Code, gc.Equals, state.MeterNotSet)

status, info, err = unit3.GetMeterStatus()
status, err = unit3.GetMeterStatus()
c.Assert(err, jc.ErrorIsNil)
c.Assert(status, gc.Equals, "NOT SET")
c.Assert(info, gc.Equals, "")
c.Assert(status.Code, gc.Equals, state.MeterNotSet)

}

Expand Down
9 changes: 4 additions & 5 deletions apiserver/uniter/uniter_base.go
Expand Up @@ -1263,17 +1263,16 @@ func (u *uniterBaseAPI) GetMeterStatus(args params.Entities) (params.MeterStatus
continue
}
err = common.ErrPerm
var code string
var info string
var status state.MeterStatus
if canAccess(unitTag) {
var unit *state.Unit
unit, err = u.getUnit(unitTag)
if err == nil {
code, info, err = unit.GetMeterStatus()
status, err = unit.GetMeterStatus()
}
result.Results[i].Code = status.Code.String()
result.Results[i].Info = status.Info
}
result.Results[i].Code = code
result.Results[i].Info = info
result.Results[i].Error = common.ServerError(err)
}
return result, nil
Expand Down
1 change: 1 addition & 0 deletions state/export_test.go
Expand Up @@ -47,6 +47,7 @@ var (
MultiEnvCollections = multiEnvCollections
PickAddress = &pickAddress
AddVolumeOp = (*State).addVolumeOp
CombineMeterStatus = combineMeterStatus
)

type (
Expand Down
105 changes: 87 additions & 18 deletions state/meterstatus.go
Expand Up @@ -13,27 +13,75 @@ import (

var meterStatusLogger = loggo.GetLogger("juju.state.meterstatus")

// MeterStatus represents the metering status of a unit.
type MeterStatus struct {
Code MeterStatusCode
Info string
}

// Severity returns relative severity of the meter status.
func (m *MeterStatus) Severity() int {
return m.Code.Severity()
}

// MeterStatusCode represents the meter status code of a unit.
type MeterStatusCode string
// The int value represents its relative severity when compared to
// other MeterStatusCodes.
type MeterStatusCode int

// Severity returns the relative severity.
func (m MeterStatusCode) Severity() int {
return int(m)
}

// String returns a human readable string representation of the meter status.
func (m MeterStatusCode) String() string {
s, ok := meterString[m]
if !ok {
return MeterNotAvailable.String()
}
return s
}

// MeterStatusFromString returns a valid MeterStatusCode given a string representation.
func MeterStatusFromString(str string) MeterStatusCode {
for m, s := range meterString {
if s == str {
return m
}
}
return MeterNotAvailable
}

// This const block defines the relative severities of the valid MeterStatusCodes in ascending order.
const (
MeterNotSet MeterStatusCode = "NOT SET"
MeterNotAvailable MeterStatusCode = "NOT AVAILABLE"
MeterGreen MeterStatusCode = "GREEN"
MeterAmber MeterStatusCode = "AMBER"
MeterRed MeterStatusCode = "RED"
MeterGreen MeterStatusCode = iota
MeterNotSet
MeterAmber
MeterRed
MeterNotAvailable
)

var (
meterString = map[MeterStatusCode]string{
MeterGreen: "GREEN",
MeterNotSet: "NOT SET",
MeterAmber: "AMBER",
MeterNotAvailable: "NOT AVAILABLE",
MeterRed: "RED",
}
)

type meterStatusDoc struct {
DocID string `bson:"_id"`
EnvUUID string `bson:"env-uuid"`
Code MeterStatusCode `bson:"code"`
Info string `bson:"info"`
DocID string `bson:"_id"`
EnvUUID string `bson:"env-uuid"`
Code string `bson:"code"`
Info string `bson:"info"`
}

// SetMeterStatus sets the meter status for the unit.
func (u *Unit) SetMeterStatus(codeRaw, info string) error {
code := MeterStatusCode(codeRaw)
func (u *Unit) SetMeterStatus(codeStr, info string) error {
code := MeterStatusFromString(codeStr)
switch code {
case MeterGreen, MeterAmber, MeterRed:
default:
Expand All @@ -43,7 +91,7 @@ func (u *Unit) SetMeterStatus(codeRaw, info string) error {
if err != nil {
return errors.Annotatef(err, "cannot update meter status for unit %s", u.Name())
}
if meterDoc.Code == code && meterDoc.Info == info {
if meterDoc.Code == code.String() && meterDoc.Info == info {
return nil
}

Expand All @@ -57,7 +105,7 @@ func (u *Unit) SetMeterStatus(codeRaw, info string) error {
if err != nil {
return nil, errors.Annotatef(err, "cannot update meter status for unit %s", u.Name())
}
if meterDoc.Code == code && meterDoc.Info == info {
if meterDoc.Code == code.String() && meterDoc.Info == info {
return nil, jujutxn.ErrNoOperations
}
}
Expand All @@ -70,7 +118,7 @@ func (u *Unit) SetMeterStatus(codeRaw, info string) error {
C: meterStatusC,
Id: u.st.docID(u.globalKey()),
Assert: txn.DocExists,
Update: bson.D{{"$set", bson.D{{"code", code}, {"info", info}}}},
Update: bson.D{{"$set", bson.D{{"code", code.String()}, {"info", info}}}},
}}, nil
}
return errors.Annotatef(u.st.run(buildTxn), "cannot set meter state for unit %s", u.Name())
Expand Down Expand Up @@ -99,12 +147,33 @@ func removeMeterStatusOp(st *State, globalKey string) txn.Op {
}

// GetMeterStatus returns the meter status for the unit.
func (u *Unit) GetMeterStatus() (code, info string, err error) {
func (u *Unit) GetMeterStatus() (MeterStatus, error) {
mm, err := u.st.MetricsManager()
if err != nil {
return MeterStatus{MeterNotAvailable, ""}, errors.Annotatef(err, "cannot retrieve meter status for metrics manager")
}

mmStatus := mm.MeterStatus()
if mmStatus.Code == MeterRed {
return mmStatus, nil
}

status, err := u.getMeterStatusDoc()
if err != nil {
return string(MeterNotAvailable), "", errors.Annotatef(err, "cannot retrieve meter status for unit %s", u.Name())
return MeterStatus{MeterNotAvailable, ""}, errors.Annotatef(err, "cannot retrieve meter status for unit %s", u.Name())
}

code := MeterStatusFromString(status.Code)

unitMeterStatus := MeterStatus{code, status.Info}
return combineMeterStatus(mmStatus, unitMeterStatus), nil
}

func combineMeterStatus(a, b MeterStatus) MeterStatus {
if a.Severity() > b.Severity() {
return a
}
return string(status.Code), status.Info, nil
return b
}

func (u *Unit) getMeterStatusDoc() (*meterStatusDoc, error) {
Expand Down