Skip to content

Commit 8f84821

Browse files
committed
Introduce bash functions to stop and start unit workers.
The introspection endpoint gains a new endpoint to handle post methods to request unit start and stop. This endpoint then uses a new simple hub to publish the request. The deployer now requires a simple hub to be passed in through the manifold rather than creating one itself. The internal stop unit message is now replaced with a centrally defined one. An additional start unit method, as well as a status method, is added. The scripts file that is written out into /etc/profile.d is updated to remove the unit agent aspects, as now there is only a machine agent. This also allows better argument passing from the other defined functions.
1 parent 4a23991 commit 8f84821

File tree

14 files changed

+584
-103
lines changed

14 files changed

+584
-103
lines changed

cmd/jujud/agent/addons/addons.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ package addons
66
import (
77
"runtime"
88

9+
"github.com/juju/clock"
910
"github.com/juju/errors"
1011
"github.com/juju/loggo"
1112
"github.com/juju/names/v4"
13+
"github.com/juju/pubsub"
1214
"github.com/juju/worker/v2"
1315
"github.com/juju/worker/v2/dependency"
1416
"github.com/prometheus/client_golang/prometheus"
@@ -38,8 +40,11 @@ type IntrospectionConfig struct {
3840
MachineLock machinelock.Lock
3941
PrometheusGatherer prometheus.Gatherer
4042
PresenceRecorder presence.Recorder
41-
NewSocketName func(names.Tag) string
42-
WorkerFunc func(config introspection.Config) (worker.Worker, error)
43+
Clock clock.Clock
44+
LocalHub *pubsub.SimpleHub
45+
46+
NewSocketName func(names.Tag) string
47+
WorkerFunc func(config introspection.Config) (worker.Worker, error)
4348
}
4449

4550
// StartIntrospection creates the introspection worker. It cannot and should
@@ -63,6 +68,8 @@ func StartIntrospection(cfg IntrospectionConfig) error {
6368
MachineLock: cfg.MachineLock,
6469
PrometheusGatherer: cfg.PrometheusGatherer,
6570
Presence: cfg.PresenceRecorder,
71+
Clock: cfg.Clock,
72+
Hub: cfg.LocalHub,
6673
})
6774
if err != nil {
6875
return errors.Trace(err)

cmd/jujud/agent/caasoperator.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ func (op *CaasOperatorAgent) Workers() (worker.Worker, error) {
258258
NewSocketName: addons.DefaultIntrospectionSocketName,
259259
PrometheusGatherer: op.prometheusRegistry,
260260
WorkerFunc: introspection.NewWorker,
261+
// If the caas operator gains the ability to interact with the
262+
// introspection worker, the introspection worker should be configured
263+
// with a clock and hub. See the machine agent.
261264
}); err != nil {
262265
// If the introspection worker failed to start, we just log error
263266
// but continue. It is very unlikely to happen in the real world

cmd/jujud/agent/machine.go

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,9 @@ func (a *MachineAgent) makeEngineCreator(
532532
if err != nil {
533533
return nil, err
534534
}
535+
localHub := pubsub.NewSimpleHub(&pubsub.SimpleHubConfig{
536+
Logger: loggo.GetLogger("juju.localhub"),
537+
})
535538
pubsubReporter := psworker.NewReporter()
536539
presenceRecorder := presence.New(clock.WallClock)
537540
updateAgentConfLogging := func(loggingConfig string) error {
@@ -570,11 +573,12 @@ func (a *MachineAgent) makeEngineCreator(
570573
StartAPIWorkers: a.startAPIWorkers,
571574
PreUpgradeSteps: a.preUpgradeSteps,
572575
LogSource: a.bufferedLogger.Logs(),
573-
NewDeployContext: newDeployContext,
576+
NewDeployContext: deployer.NewNestedContext,
574577
Clock: clock.WallClock,
575578
ValidateMigration: a.validateMigration,
576579
PrometheusRegisterer: a.prometheusRegistry,
577580
CentralHub: a.centralHub,
581+
LocalHub: localHub,
578582
PubSubReporter: pubsubReporter,
579583
PresenceRecorder: presenceRecorder,
580584
UpdateLoggerConfig: updateAgentConfLogging,
@@ -616,6 +620,8 @@ func (a *MachineAgent) makeEngineCreator(
616620
PrometheusGatherer: a.prometheusRegistry,
617621
PresenceRecorder: presenceRecorder,
618622
WorkerFunc: introspection.NewWorker,
623+
Clock: clock.WallClock,
624+
LocalHub: localHub,
619625
}); err != nil {
620626
// If the introspection worker failed to start, we just log error
621627
// but continue. It is very unlikely to happen in the real world
@@ -1356,15 +1362,6 @@ func (a *MachineAgent) removeJujudSymlinks() (errs []error) {
13561362
return
13571363
}
13581364

1359-
// newDeployContext gives the tests the opportunity to create a deployer.Context
1360-
// that can be used for testing so as to avoid (1) deploying units to the system
1361-
// running the tests and (2) get access to the *State used internally, so that
1362-
// tests can be run without waiting for the 5s watcher refresh time to which we would
1363-
// otherwise be restricted.
1364-
var newDeployContext = func(config deployer.ContextConfig) (deployer.Context, error) {
1365-
return deployer.NewNestedContext(config)
1366-
}
1367-
13681365
// statePoolIntrospectionReporter wraps a (possibly nil) state.StatePool,
13691366
// calling its IntrospectionReport method or returning a message if it
13701367
// is nil.

cmd/jujud/agent/machine/manifolds.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,11 @@ type ManifoldsConfig struct {
197197
// CentralHub is the primary hub that exists in the apiserver.
198198
CentralHub *pubsub.StructuredHub
199199

200+
// LocalHub is a simple pubsub that is used for internal agent
201+
// messaging only. This is used for interactions between workers
202+
// and the introspection worker.
203+
LocalHub *pubsub.SimpleHub
204+
200205
// PubSubReporter is the introspection reporter for the pubsub forwarding
201206
// worker.
202207
PubSubReporter psworker.Reporter
@@ -958,6 +963,7 @@ func IAASManifolds(config ManifoldsConfig) dependency.Manifolds {
958963
AgentName: agentName,
959964
APICallerName: apiCallerName,
960965
Clock: config.Clock,
966+
Hub: config.LocalHub,
961967
Logger: loggo.GetLogger("juju.worker.deployer"),
962968

963969
UnitEngineConfig: config.UnitEngineConfig,

cmd/jujud/introspect/introspect.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/juju/errors"
1818
"github.com/juju/gnuflag"
1919
"github.com/juju/names/v4"
20+
"github.com/kr/pretty"
2021

2122
apiagent "github.com/juju/juju/api/agent"
2223
jujucmd "github.com/juju/juju/cmd"
@@ -31,8 +32,9 @@ type IntrospectCommand struct {
3132
path string
3233
listen string
3334

34-
post bool
35-
form url.Values
35+
verbose bool
36+
post bool
37+
form url.Values
3638

3739
// IntrospectionSocketName returns the socket name
3840
// for a given tag. If IntrospectionSocketName is nil,
@@ -83,6 +85,7 @@ func (c *IntrospectCommand) SetFlags(f *gnuflag.FlagSet) {
8385
f.StringVar(&c.agent, "agent", "", "agent to introspect (defaults to machine agent)")
8486
f.StringVar(&c.listen, "listen", "", "address on which to expose the introspection socket")
8587
f.BoolVar(&c.post, "post", false, "perform a POST action rather than a GET")
88+
f.BoolVar(&c.verbose, "verbose", false, "show query path and args")
8689
}
8790

8891
func (c *IntrospectCommand) Init(args []string) error {
@@ -141,12 +144,17 @@ func (c *IntrospectCommand) Run(ctx *cmd.Context) error {
141144
return http.Serve(listener, proxy)
142145
}
143146

144-
ctx.Infof("Querying %s introspection socket: %s", socketName, c.path)
145147
client := unixSocketHTTPClient(socketName)
146148
var resp *http.Response
147149
if c.post {
150+
if c.verbose {
151+
ctx.Infof("Posting to %s introspection socket: %s %s", socketName, c.path, pretty.Sprint(c.form))
152+
}
148153
resp, err = client.PostForm(targetURL.String(), c.form)
149154
} else {
155+
if c.verbose {
156+
ctx.Infof("Querying %s introspection socket: %s", socketName, c.path)
157+
}
150158
resp, err = client.Get(targetURL.String())
151159
}
152160
if err != nil {

cmd/jujud/introspect/introspect_test.go

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,18 +112,12 @@ func (s *IntrospectCommandSuite) TestQueryFails(c *gc.C) {
112112

113113
ctx, err := s.run(c, "missing", "--agent=machine-0")
114114
c.Assert(err.Error(), gc.Equals, "response returned 404 (Not Found)")
115-
c.Assert(cmdtesting.Stderr(ctx), gc.Equals, fmt.Sprintf(`
116-
Querying @%s introspection socket: missing
117-
404 page not found
118-
`[1:], filepath.Join(config.DataDir, "jujud-machine-0")))
115+
c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "404 page not found\n")
119116
c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "")
120117

121118
ctx, err = s.run(c, "badness", "--agent=machine-0")
122119
c.Assert(err.Error(), gc.Equals, "response returned 500 (Internal Server Error)")
123-
c.Assert(cmdtesting.Stderr(ctx), gc.Equals, fmt.Sprintf(`
124-
Querying @%s introspection socket: badness
125-
argh
126-
`[1:], filepath.Join(config.DataDir, "jujud-machine-0")))
120+
c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "argh\n")
127121
c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "")
128122
}
129123

@@ -138,10 +132,7 @@ func (s *IntrospectCommandSuite) TestGetToPostEndpoint(c *gc.C) {
138132

139133
ctx, err := s.run(c, "postonly", "--agent=machine-0")
140134
c.Assert(err, gc.ErrorMatches, `response returned 405 \(Method Not Allowed\)`)
141-
c.Assert(cmdtesting.Stderr(ctx), gc.Equals, fmt.Sprintf(`
142-
Querying @%s introspection socket: postonly
143-
postonly requires a POST request
144-
`[1:], filepath.Join(config.DataDir, "jujud-machine-0")))
135+
c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "postonly requires a POST request\n")
145136
c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "")
146137
}
147138

cmd/k8sagent/unit/agent.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ func (c *k8sUnitAgent) workers() (worker.Worker, error) {
192192
NewSocketName: addons.DefaultIntrospectionSocketName,
193193
PrometheusGatherer: c.prometheusRegistry,
194194
WorkerFunc: introspection.NewWorker,
195+
// If the k8sagent gains the ability to interact with the introspection
196+
// worker, the introspection worker should be configured with a clock
197+
// and hub. See the machine agent.
195198
}); err != nil {
196199
// If the introspection worker failed to start, we just log error
197200
// but continue. It is very unlikely to happen in the real world

pubsub/agent/messages.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2020 Canonical Ltd.
2+
// Licensed under the AGPLv3, see LICENCE file for details.
3+
4+
// Package agent contains messages for all agents rather than controllers.
5+
//
6+
// All these structures are expected to be used with a SimpleHub that doesn't
7+
// seralize, hence no serialization directives.
8+
package agent
9+
10+
// StartUnitTopic is used to request one or more units to start.
11+
// The payload for a StartUnitTopic is the Units structure.
12+
const StartUnitTopic = "unit.start"
13+
14+
// StopUnitTopic is used to request one or more units to stop.
15+
// The payload for a StopUnitTopic is the Units structure.
16+
const StopUnitTopic = "unit.stop"
17+
18+
// UnitStatusTopic is used to request the current status for the units.
19+
// There is no payload for this request.
20+
const UnitStatusTopic = "unit.status"
21+
22+
// UnitStatusResponseTopic is the topic to respond to a status request.
23+
// The payload is the Status type below.
24+
const UnitStatusResponseTopic = "unit.status.response"
25+
26+
// Units provides a way to request start or stop multiple units.
27+
type Units struct {
28+
Names []string
29+
}
30+
31+
// Status is a map of unit name to the status value. An interace{} value is returned
32+
// to allow for simple expansion later. The output of the status is expected to just
33+
// show a nice string representation of the map.
34+
type Status map[string]interface{}

worker/deployer/manifold.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@ import (
1717
"github.com/juju/juju/cmd/jujud/agent/engine"
1818
)
1919

20+
// Hub is a pubsub hub used for internal messaging.
21+
type Hub interface {
22+
Publish(topic string, data interface{}) <-chan struct{}
23+
Subscribe(topic string, handler func(string, interface{})) func()
24+
}
25+
2026
// ManifoldConfig defines the names of the manifolds on which a Manifold will depend.
2127
type ManifoldConfig struct {
2228
AgentName string
2329
APICallerName string
2430
Clock clock.Clock
31+
Hub Hub
2532
Logger Logger
2633

2734
UnitEngineConfig func() dependency.EngineConfig
@@ -56,6 +63,7 @@ func (config ManifoldConfig) newWorker(a agent.Agent, apiCaller base.APICaller)
5663
contextConfig := ContextConfig{
5764
Agent: a,
5865
Clock: config.Clock,
66+
Hub: config.Hub,
5967
Logger: config.Logger,
6068
UnitEngineConfig: config.UnitEngineConfig,
6169
SetupLogging: config.SetupLogging,

0 commit comments

Comments
 (0)