Skip to content

Commit

Permalink
Weave the new presence code through the apiserver.
Browse files Browse the repository at this point in the history
  • Loading branch information
howbazaar committed Apr 16, 2018
1 parent 9ceeab1 commit 1449cfa
Show file tree
Hide file tree
Showing 32 changed files with 497 additions and 125 deletions.
1 change: 1 addition & 0 deletions apiserver/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ func (a *admin) login(req params.LoginRequest, loginVersion int) (params.LoginRe
a.srv.facades,
a.root.resources,
a.root,
a.root.presence,
)
apiRoot, err = restrictAPIRoot(
a.srv,
Expand Down
7 changes: 7 additions & 0 deletions apiserver/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/juju/juju/apiserver/observer"
"github.com/juju/juju/apiserver/websocket"
"github.com/juju/juju/core/auditlog"
"github.com/juju/juju/core/presence"
"github.com/juju/juju/resource"
"github.com/juju/juju/resource/resourceadapters"
"github.com/juju/juju/rpc"
Expand Down Expand Up @@ -66,6 +67,7 @@ type Server struct {
offerAuthCtxt *crossmodel.AuthContext
lastConnectionID uint64
centralHub *pubsub.StructuredHub
presence presence.Recorder
newObserver observer.ObserverFactory
connCount int64
totalConn int64
Expand Down Expand Up @@ -104,6 +106,7 @@ type ServerConfig struct {
DataDir string
LogDir string
Hub *pubsub.StructuredHub
Presence presence.Recorder
Mux *apiserverhttp.Mux
Authenticator httpcontext.LocalMacaroonAuthenticator

Expand Down Expand Up @@ -170,6 +173,9 @@ func (c ServerConfig) Validate() error {
if c.Hub == nil {
return errors.NotValidf("missing Hub")
}
if c.Presence == nil {
return errors.NotValidf("missing Presence")
}
if c.Mux == nil {
return errors.NotValidf("missing Mux")
}
Expand Down Expand Up @@ -246,6 +252,7 @@ func newServer(cfg ServerConfig) (_ *Server, err error) {
restoreStatus: cfg.RestoreStatus,
facades: AllFacades(),
centralHub: cfg.Hub,
presence: cfg.Presence,
mux: cfg.Mux,
authenticator: cfg.Authenticator,
allowModelAccess: cfg.AllowModelAccess,
Expand Down
2 changes: 2 additions & 0 deletions apiserver/apiserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/juju/juju/apiserver/stateauthenticator"
apitesting "github.com/juju/juju/apiserver/testing"
"github.com/juju/juju/core/auditlog"
"github.com/juju/juju/core/presence"
"github.com/juju/juju/pubsub/centralhub"
"github.com/juju/juju/state"
statetesting "github.com/juju/juju/state/testing"
Expand Down Expand Up @@ -79,6 +80,7 @@ func (s *apiserverConfigFixture) SetUpTest(c *gc.C) {
DataDir: c.MkDir(),
LogDir: c.MkDir(),
Hub: centralhub.New(machineTag),
Presence: presence.New(clock.WallClock),
Mux: s.mux,
NewObserver: func() observer.Observer { return &fakeobserver.Instance{} },
RateLimitConfig: apiserver.DefaultRateLimitConfig(),
Expand Down
4 changes: 3 additions & 1 deletion apiserver/common/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ func ModelMachineInfo(st ModelManagerBackend) (machineInfo []params.ModelMachine
continue
}
var status string
statusInfo, err := MachineStatus(m)
// This is suboptimal as if there are many machines,
// we are making many calls into the DB for each machine.
statusInfo, err := m.Status()
if err == nil {
status = string(statusInfo.Status)
} else {
Expand Down
4 changes: 2 additions & 2 deletions apiserver/common/machinestatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type MachineStatusGetter interface {

// MachineStatus returns the machine agent status for a given
// machine, with special handling for agent presence.
func MachineStatus(machine MachineStatusGetter) (status.StatusInfo, error) {
func (c *ModelPresenceContext) MachineStatus(machine MachineStatusGetter) (status.StatusInfo, error) {
machineStatus, err := machine.Status()
if err != nil {
return status.StatusInfo{}, err
Expand All @@ -31,7 +31,7 @@ func MachineStatus(machine MachineStatusGetter) (status.StatusInfo, error) {
return machineStatus, nil
}

agentAlive, err := machine.AgentPresence()
agentAlive, err := c.machinePresence(machine)
if err != nil {
// We don't want any presence errors affecting status.
logger.Debugf("error determining presence for machine %s: %v", machine.Id(), err)
Expand Down
51 changes: 44 additions & 7 deletions apiserver/common/machinestatus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,23 @@ import (

type MachineStatusSuite struct {
testing.IsolationSuite
ctx common.ModelPresenceContext
machine *mockMachine
}

var _ = gc.Suite(&MachineStatusSuite{})

func (s *MachineStatusSuite) SetUpTest(c *gc.C) {
s.ctx = common.ModelPresenceContext{
Presence: allAlive(),
}
s.machine = &mockMachine{
status: status.Started,
}
}

func (s *MachineStatusSuite) checkUntouched(c *gc.C) {
agent, err := common.MachineStatus(s.machine)
agent, err := s.ctx.MachineStatus(s.machine)
c.Check(err, jc.ErrorIsNil)
c.Assert(agent.Status, jc.DeepEquals, s.machine.status)
}
Expand All @@ -41,36 +45,69 @@ func (s *MachineStatusSuite) TestNormal(c *gc.C) {
func (s *MachineStatusSuite) TestErrors(c *gc.C) {
s.machine.statusErr = errors.New("status error")

_, err := common.MachineStatus(s.machine)
_, err := s.ctx.MachineStatus(s.machine)
c.Assert(err, gc.ErrorMatches, "status error")
}

func (s *MachineStatusSuite) TestDown(c *gc.C) {
func (s *MachineStatusSuite) TestDownLegacy(c *gc.C) {
s.ctx.Presence = nil
s.machine.agentDead = true
agent, err := common.MachineStatus(s.machine)
agent, err := s.ctx.MachineStatus(s.machine)
c.Assert(err, jc.ErrorIsNil)
c.Assert(agent, jc.DeepEquals, status.StatusInfo{
Status: status.Down,
Message: "agent is not communicating with the server",
})
}

func (s *MachineStatusSuite) TestDownAndDead(c *gc.C) {
func (s *MachineStatusSuite) TestDown(c *gc.C) {
s.ctx.Presence = agentsDown()
agent, err := s.ctx.MachineStatus(s.machine)
c.Assert(err, jc.ErrorIsNil)
c.Assert(agent, jc.DeepEquals, status.StatusInfo{
Status: status.Down,
Message: "agent is not communicating with the server",
})
}

func (s *MachineStatusSuite) TestDownAndDeadLegacy(c *gc.C) {
s.ctx.Presence = nil
s.machine.agentDead = true
s.machine.life = state.Dead
// Status is untouched if unit is Dead.
s.checkUntouched(c)
}

func (s *MachineStatusSuite) TestPresenceError(c *gc.C) {
func (s *MachineStatusSuite) TestDownAndDead(c *gc.C) {
s.ctx.Presence = agentsDown()
s.machine.life = state.Dead
// Status is untouched if unit is Dead.
s.checkUntouched(c)
}

func (s *MachineStatusSuite) TestPresenceErrorLegacy(c *gc.C) {
s.ctx.Presence = nil
s.machine.agentDead = true
s.machine.presenceErr = errors.New("boom")
// Presence error gets ignored, so no output is unchanged.
s.checkUntouched(c)
}

func (s *MachineStatusSuite) TestNotDownIfPending(c *gc.C) {
func (s *MachineStatusSuite) TestPresenceError(c *gc.C) {
s.ctx.Presence = presenceError()
// Presence error gets ignored, so no output is unchanged.
s.checkUntouched(c)
}

func (s *MachineStatusSuite) TestNotDownIfPendingLegacy(c *gc.C) {
s.ctx.Presence = nil
s.machine.agentDead = true
s.machine.status = status.Pending
s.checkUntouched(c)
}

func (s *MachineStatusSuite) TestNotDownIfPending(c *gc.C) {
s.ctx.Presence = agentsDown()
s.machine.status = status.Pending
s.checkUntouched(c)
}
42 changes: 42 additions & 0 deletions apiserver/common/presence.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2018 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package common

import (
"gopkg.in/juju/names.v2"

"github.com/juju/juju/core/presence"
)

// ModelPresence represents the API server connections for a model.
type ModelPresence interface {
// For a given non controller agent, return the Status for that agent.
AgentStatus(agent string) (presence.Status, error)
}

// ModelPresenceContext represents the known agent presence state for the
// entire model.
type ModelPresenceContext struct {
// Presence represents the API server connections for a model.
// If this is non-nil it is used in preference to the state AgentPresence method.
Presence ModelPresence
}

func (c *ModelPresenceContext) machinePresence(machine MachineStatusGetter) (bool, error) {
if c.Presence == nil {
return machine.AgentPresence()
}
agent := names.NewMachineTag(machine.Id())
status, err := c.Presence.AgentStatus(agent.String())
return status == presence.Alive, err
}

func (c *ModelPresenceContext) unitPresence(unit UnitStatusGetter) (bool, error) {
if c.Presence == nil {
return unit.AgentPresence()
}
agent := names.NewUnitTag(unit.Name())
status, err := c.Presence.AgentStatus(agent.String())
return status == presence.Alive, err
}
32 changes: 32 additions & 0 deletions apiserver/common/presence_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2018 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package common_test

import (
"github.com/juju/errors"

"github.com/juju/juju/apiserver/common"
"github.com/juju/juju/core/presence"
)

func allAlive() common.ModelPresence {
return &fakeModelPresence{status: presence.Alive}
}

func agentsDown() common.ModelPresence {
return &fakeModelPresence{status: presence.Missing}
}

func presenceError() common.ModelPresence {
return &fakeModelPresence{err: errors.New("boom")}
}

type fakeModelPresence struct {
status presence.Status
err error
}

func (f *fakeModelPresence) AgentStatus(agent string) (presence.Status, error) {
return f.status, f.err
}
4 changes: 2 additions & 2 deletions apiserver/common/unitstatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type UnitStatusGetter interface {

// UnitStatus returns the unit agent and workload status for a given
// unit, with special handling for agent presence.
func UnitStatus(unit UnitStatusGetter) (agent StatusAndErr, workload StatusAndErr) {
func (c *ModelPresenceContext) UnitStatus(unit UnitStatusGetter) (agent StatusAndErr, workload StatusAndErr) {
agent.Status, agent.Err = unit.AgentStatus()
workload.Status, workload.Err = unit.Status()

Expand All @@ -42,7 +42,7 @@ func UnitStatus(unit UnitStatusGetter) (agent StatusAndErr, workload StatusAndEr
return
}

agentAlive, err := unit.AgentPresence()
agentAlive, err := c.unitPresence(unit)
if err != nil {
return
}
Expand Down
Loading

0 comments on commit 1449cfa

Please sign in to comment.