Merge lp:~axwalk/juju-core/agent-watch-apihostports into lp:~go-bot/juju-core/trunk

Proposed by Andrew Wilkins
Status: Merged
Approved by: Andrew Wilkins
Approved revision: no longer in the source branch.
Merged at revision: 2539
Proposed branch: lp:~axwalk/juju-core/agent-watch-apihostports
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 327 lines (+230/-0)
7 files modified
cmd/jujud/agent.go (+8/-0)
cmd/jujud/machine.go (+4/-0)
cmd/jujud/machine_test.go (+26/-0)
cmd/jujud/unit.go (+4/-0)
cmd/jujud/unit_test.go (+27/-0)
worker/apiaddressupdater/apiaddressupdater.go (+64/-0)
worker/apiaddressupdater/apiaddressupdater_test.go (+97/-0)
To merge this branch: bzr merge lp:~axwalk/juju-core/agent-watch-apihostports
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+213778@code.launchpad.net

Commit message

Introduce worker/apiaddressupdater

This proposal introduces a new worker that
watches changes to APIHostPorts, and then
updates agent config. The machine and unit
agents have both been updated to start this
worker.

https://codereview.appspot.com/83500043/

Description of the change

Introduce worker/apiaddressupdater

This proposal introduces a new worker that
watches changes to APIHostPorts, and then
updates agent config. The machine and unit
agents have both been updated to start this
worker.

https://codereview.appspot.com/83500043/

To post a comment you must log in.
Revision history for this message
Andrew Wilkins (axwalk) wrote :

Reviewers: mp+213778_code.launchpad.net,

Message:
Please take a look.

Description:
Introduce worker/apiaddressupdater

This proposal introduces a new worker that
watches changes to APIHostPorts, and then
updates agent config. The machine and unit
agents have both been updated to start this
worker.

https://code.launchpad.net/~axwalk/juju-core/agent-watch-apihostports/+merge/213778

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/83500043/

Affected files (+242, -0 lines):
   A [revision details]
   M cmd/jujud/agent.go
   M cmd/jujud/machine.go
   M cmd/jujud/machine_test.go
   M cmd/jujud/unit.go
   M cmd/jujud/unit_test.go
   A worker/apiaddressupdater/apiaddressupdater.go
   A worker/apiaddressupdater/apiaddressupdater_test.go

Revision history for this message
Roger Peppe (rogpeppe) wrote :

LGTM with a few queries below, thanks!

https://codereview.appspot.com/83500043/diff/1/cmd/jujud/machine_test.go
File cmd/jujud/machine_test.go (right):

https://codereview.appspot.com/83500043/diff/1/cmd/jujud/machine_test.go#newcode851
cmd/jujud/machine_test.go:851: s.State.StartSync()
shouldn't this be BackingState? (i think the watcher is actually in the
API, right?)

https://codereview.appspot.com/83500043/diff/1/cmd/jujud/machine_test.go#newcode852
cmd/jujud/machine_test.go:852: timeout :=
time.After(coretesting.LongWait)
perhaps this might be better phrased as an attempt loop?

https://codereview.appspot.com/83500043/diff/1/cmd/jujud/unit_test.go
File cmd/jujud/unit_test.go (right):

https://codereview.appspot.com/83500043/diff/1/cmd/jujud/unit_test.go#newcode270
cmd/jujud/unit_test.go:270: s.State.StartSync()
shouldn't this be BackingState?

https://codereview.appspot.com/83500043/

Revision history for this message
Andrew Wilkins (axwalk) wrote :

Please take a look.

https://codereview.appspot.com/83500043/diff/1/cmd/jujud/machine_test.go
File cmd/jujud/machine_test.go (right):

https://codereview.appspot.com/83500043/diff/1/cmd/jujud/machine_test.go#newcode851
cmd/jujud/machine_test.go:851: s.State.StartSync()
On 2014/04/02 08:51:08, rog wrote:
> shouldn't this be BackingState? (i think the watcher is actually in
the API,
> right?)

Done.

https://codereview.appspot.com/83500043/diff/1/cmd/jujud/machine_test.go#newcode852
cmd/jujud/machine_test.go:852: timeout :=
time.After(coretesting.LongWait)
On 2014/04/02 08:51:08, rog wrote:
> perhaps this might be better phrased as an attempt loop?

Done, much nicer.

https://codereview.appspot.com/83500043/diff/1/cmd/jujud/unit_test.go
File cmd/jujud/unit_test.go (right):

https://codereview.appspot.com/83500043/diff/1/cmd/jujud/unit_test.go#newcode270
cmd/jujud/unit_test.go:270: s.State.StartSync()
On 2014/04/02 08:51:08, rog wrote:
> shouldn't this be BackingState?

Done.

https://codereview.appspot.com/83500043/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cmd/jujud/agent.go'
2--- cmd/jujud/agent.go 2014-03-28 13:24:36 +0000
3+++ cmd/jujud/agent.go 2014-04-02 09:44:43 +0000
4@@ -13,6 +13,7 @@
5
6 "launchpad.net/juju-core/agent"
7 "launchpad.net/juju-core/cmd"
8+ "launchpad.net/juju-core/instance"
9 "launchpad.net/juju-core/log"
10 "launchpad.net/juju-core/state"
11 "launchpad.net/juju-core/state/api"
12@@ -82,6 +83,13 @@
13 return ch._config.Clone()
14 }
15
16+// SetAPIHostPorts satisfies worker/apiaddressupdater/APIAddressSetter.
17+func (a *AgentConf) SetAPIHostPorts(servers [][]instance.HostPort) error {
18+ return a.ChangeConfig(func(c agent.ConfigSetter) {
19+ c.SetAPIHostPorts(servers)
20+ })
21+}
22+
23 func importance(err error) int {
24 switch {
25 case err == nil:
26
27=== modified file 'cmd/jujud/machine.go'
28--- cmd/jujud/machine.go 2014-03-28 10:11:59 +0000
29+++ cmd/jujud/machine.go 2014-04-02 09:44:43 +0000
30@@ -33,6 +33,7 @@
31 "launchpad.net/juju-core/utils"
32 "launchpad.net/juju-core/version"
33 "launchpad.net/juju-core/worker"
34+ "launchpad.net/juju-core/worker/apiaddressupdater"
35 "launchpad.net/juju-core/worker/authenticationworker"
36 "launchpad.net/juju-core/worker/charmrevisionworker"
37 "launchpad.net/juju-core/worker/cleaner"
38@@ -212,6 +213,9 @@
39 a.startWorkerAfterUpgrade(runner, "machiner", func() (worker.Worker, error) {
40 return machiner.NewMachiner(st.Machiner(), agentConfig), nil
41 })
42+ a.startWorkerAfterUpgrade(runner, "apiaddressupdater", func() (worker.Worker, error) {
43+ return apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), a), nil
44+ })
45 a.startWorkerAfterUpgrade(runner, "logger", func() (worker.Worker, error) {
46 return workerlogger.NewLogger(st.Logger(), agentConfig), nil
47 })
48
49=== modified file 'cmd/jujud/machine_test.go'
50--- cmd/jujud/machine_test.go 2014-04-01 00:12:08 +0000
51+++ cmd/jujud/machine_test.go 2014-04-02 09:44:43 +0000
52@@ -833,6 +833,32 @@
53 })
54 }
55
56+func (s *MachineSuite) TestMachineAgentRunsAPIAddressUpdaterWorker(c *gc.C) {
57+ // Start the machine agent.
58+ m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits)
59+ a := s.newAgent(c, m)
60+ go func() { c.Check(a.Run(nil), gc.IsNil) }()
61+ defer func() { c.Check(a.Stop(), gc.IsNil) }()
62+
63+ // Update the API addresses.
64+ updatedServers := [][]instance.HostPort{instance.AddressesWithPort(
65+ instance.NewAddresses("localhost"), 1234,
66+ )}
67+ err := s.BackingState.SetAPIHostPorts(updatedServers)
68+ c.Assert(err, gc.IsNil)
69+
70+ // Wait for config to be updated.
71+ s.BackingState.StartSync()
72+ for attempt := coretesting.LongAttempt.Start(); attempt.Next(); {
73+ addrs, err := a.CurrentConfig().APIAddresses()
74+ c.Assert(err, gc.IsNil)
75+ if reflect.DeepEqual(addrs, []string{"localhost:1234"}) {
76+ return
77+ }
78+ }
79+ c.Fatalf("timeout while waiting for agent config to change")
80+}
81+
82 // MachineWithCharmsSuite provides infrastructure for tests which need to
83 // work with charms.
84 type MachineWithCharmsSuite struct {
85
86=== modified file 'cmd/jujud/unit.go'
87--- cmd/jujud/unit.go 2014-03-27 18:25:41 +0000
88+++ cmd/jujud/unit.go 2014-04-02 09:44:43 +0000
89@@ -15,6 +15,7 @@
90 "launchpad.net/juju-core/names"
91 "launchpad.net/juju-core/version"
92 "launchpad.net/juju-core/worker"
93+ "launchpad.net/juju-core/worker/apiaddressupdater"
94 workerlogger "launchpad.net/juju-core/worker/logger"
95 "launchpad.net/juju-core/worker/rsyslog"
96 "launchpad.net/juju-core/worker/uniter"
97@@ -96,6 +97,9 @@
98 runner.StartWorker("uniter", func() (worker.Worker, error) {
99 return uniter.NewUniter(st.Uniter(), entity.Tag(), dataDir), nil
100 })
101+ runner.StartWorker("apiaddressupdater", func() (worker.Worker, error) {
102+ return apiaddressupdater.NewAPIAddressUpdater(st.Uniter(), a), nil
103+ })
104 runner.StartWorker("rsyslog", func() (worker.Worker, error) {
105 return newRsyslogConfigWorker(st.Rsyslog(), agentConfig, rsyslog.RsyslogModeForwarding)
106 })
107
108=== modified file 'cmd/jujud/unit_test.go'
109--- cmd/jujud/unit_test.go 2014-03-28 08:28:04 +0000
110+++ cmd/jujud/unit_test.go 2014-04-02 09:44:43 +0000
111@@ -4,6 +4,7 @@
112 package main
113
114 import (
115+ "reflect"
116 "time"
117
118 gc "launchpad.net/gocheck"
119@@ -11,6 +12,7 @@
120 "launchpad.net/juju-core/agent"
121 "launchpad.net/juju-core/cmd"
122 envtesting "launchpad.net/juju-core/environs/testing"
123+ "launchpad.net/juju-core/instance"
124 jujutesting "launchpad.net/juju-core/juju/testing"
125 "launchpad.net/juju-core/names"
126 "launchpad.net/juju-core/state"
127@@ -250,3 +252,28 @@
128 c.Assert(mode, gc.Equals, rsyslog.RsyslogModeForwarding)
129 }
130 }
131+
132+func (s *UnitSuite) TestUnitAgentRunsAPIAddressUpdaterWorker(c *gc.C) {
133+ _, unit, _, _ := s.primeAgent(c)
134+ a := s.newAgent(c, unit)
135+ go func() { c.Check(a.Run(nil), gc.IsNil) }()
136+ defer func() { c.Check(a.Stop(), gc.IsNil) }()
137+
138+ // Update the API addresses.
139+ updatedServers := [][]instance.HostPort{instance.AddressesWithPort(
140+ instance.NewAddresses("localhost"), 1234,
141+ )}
142+ err := s.BackingState.SetAPIHostPorts(updatedServers)
143+ c.Assert(err, gc.IsNil)
144+
145+ // Wait for config to be updated.
146+ s.BackingState.StartSync()
147+ for attempt := coretesting.LongAttempt.Start(); attempt.Next(); {
148+ addrs, err := a.CurrentConfig().APIAddresses()
149+ c.Assert(err, gc.IsNil)
150+ if reflect.DeepEqual(addrs, []string{"localhost:1234"}) {
151+ return
152+ }
153+ }
154+ c.Fatalf("timeout while waiting for agent config to change")
155+}
156
157=== added directory 'worker/apiaddressupdater'
158=== added file 'worker/apiaddressupdater/apiaddressupdater.go'
159--- worker/apiaddressupdater/apiaddressupdater.go 1970-01-01 00:00:00 +0000
160+++ worker/apiaddressupdater/apiaddressupdater.go 2014-04-02 09:44:43 +0000
161@@ -0,0 +1,64 @@
162+// Copyright 2014 Canonical Ltd.
163+// Licensed under the AGPLv3, see LICENCE file for details.
164+
165+package apiaddressupdater
166+
167+import (
168+ "fmt"
169+
170+ "github.com/juju/loggo"
171+
172+ "launchpad.net/juju-core/instance"
173+ "launchpad.net/juju-core/state/api/watcher"
174+ "launchpad.net/juju-core/worker"
175+)
176+
177+var logger = loggo.GetLogger("juju.worker.apiaddressupdater")
178+
179+// APIAddressUpdater is responsible for cleaning up the state.
180+type APIAddressUpdater struct {
181+ addresser APIAddresser
182+ setter APIAddressSetter
183+}
184+
185+// APIAddresser is an interface that is provided to NewAPIAddressUpdater
186+// which can be used to watch for API address changes.
187+type APIAddresser interface {
188+ APIHostPorts() ([][]instance.HostPort, error)
189+ WatchAPIHostPorts() (watcher.NotifyWatcher, error)
190+}
191+
192+// APIAddressSetter is an interface that is provided to NewAPIAddressUpdater
193+// whose SetAPIHostPorts method will be invoked whenever address changes occur.
194+type APIAddressSetter interface {
195+ SetAPIHostPorts(servers [][]instance.HostPort) error
196+}
197+
198+// NewAPIAddressUpdater returns a worker.Worker that runs state.Cleanup()
199+// if the CleanupWatcher signals documents marked for deletion.
200+func NewAPIAddressUpdater(addresser APIAddresser, setter APIAddressSetter) worker.Worker {
201+ return worker.NewNotifyWorker(&APIAddressUpdater{
202+ addresser: addresser,
203+ setter: setter,
204+ })
205+}
206+
207+func (c *APIAddressUpdater) SetUp() (watcher.NotifyWatcher, error) {
208+ return c.addresser.WatchAPIHostPorts()
209+}
210+
211+func (c *APIAddressUpdater) Handle() error {
212+ addresses, err := c.addresser.APIHostPorts()
213+ if err != nil {
214+ return fmt.Errorf("error getting addresses: %v", err)
215+ }
216+ if err := c.setter.SetAPIHostPorts(addresses); err != nil {
217+ return fmt.Errorf("error setting addresses: %v", err)
218+ }
219+ logger.Infof("API addresses updated to %q", addresses)
220+ return nil
221+}
222+
223+func (c *APIAddressUpdater) TearDown() error {
224+ return nil
225+}
226
227=== added file 'worker/apiaddressupdater/apiaddressupdater_test.go'
228--- worker/apiaddressupdater/apiaddressupdater_test.go 1970-01-01 00:00:00 +0000
229+++ worker/apiaddressupdater/apiaddressupdater_test.go 2014-04-02 09:44:43 +0000
230@@ -0,0 +1,97 @@
231+// Copyright 2014 Canonical Ltd.
232+// Licensed under the AGPLv3, see LICENCE file for details.
233+
234+package apiaddressupdater_test
235+
236+import (
237+ stdtesting "testing"
238+ "time"
239+
240+ gc "launchpad.net/gocheck"
241+
242+ "launchpad.net/juju-core/instance"
243+ jujutesting "launchpad.net/juju-core/juju/testing"
244+ "launchpad.net/juju-core/state"
245+ coretesting "launchpad.net/juju-core/testing"
246+ "launchpad.net/juju-core/worker/apiaddressupdater"
247+)
248+
249+func TestPackage(t *stdtesting.T) {
250+ coretesting.MgoTestPackage(t)
251+}
252+
253+type APIAddressUpdaterSuite struct {
254+ jujutesting.JujuConnSuite
255+}
256+
257+var _ = gc.Suite(&APIAddressUpdaterSuite{})
258+
259+type apiAddressSetter struct {
260+ servers chan [][]instance.HostPort
261+ err error
262+}
263+
264+func (s *apiAddressSetter) SetAPIHostPorts(servers [][]instance.HostPort) error {
265+ s.servers <- servers
266+ return s.err
267+}
268+
269+func (s *APIAddressUpdaterSuite) TestStartStop(c *gc.C) {
270+ st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits)
271+ worker := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), &apiAddressSetter{})
272+ worker.Kill()
273+ c.Assert(worker.Wait(), gc.IsNil)
274+}
275+
276+func (s *APIAddressUpdaterSuite) TestAddressInitialUpdate(c *gc.C) {
277+ updatedServers := [][]instance.HostPort{instance.AddressesWithPort(
278+ instance.NewAddresses("localhost", "127.0.0.1"),
279+ 1234,
280+ )}
281+ err := s.State.SetAPIHostPorts(updatedServers)
282+ c.Assert(err, gc.IsNil)
283+
284+ setter := &apiAddressSetter{servers: make(chan [][]instance.HostPort, 1)}
285+ st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits)
286+ worker := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), setter)
287+ defer func() { c.Assert(worker.Wait(), gc.IsNil) }()
288+ defer worker.Kill()
289+
290+ // SetAPIHostPorts should be called with the initial value.
291+ select {
292+ case <-time.After(coretesting.LongWait):
293+ c.Fatalf("timed out waiting for SetAPIHostPorts to be called")
294+ case servers := <-setter.servers:
295+ c.Assert(servers, gc.DeepEquals, updatedServers)
296+ }
297+}
298+
299+func (s *APIAddressUpdaterSuite) TestAddressChange(c *gc.C) {
300+ setter := &apiAddressSetter{servers: make(chan [][]instance.HostPort, 1)}
301+ st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits)
302+ worker := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), setter)
303+ defer func() { c.Assert(worker.Wait(), gc.IsNil) }()
304+ defer worker.Kill()
305+
306+ updatedServers := [][]instance.HostPort{instance.AddressesWithPort(
307+ instance.NewAddresses("localhost", "127.0.0.1"),
308+ 1234,
309+ )}
310+ err := s.State.SetAPIHostPorts(updatedServers)
311+ c.Assert(err, gc.IsNil)
312+
313+ // SetAPIHostPorts should be called with the initial value (empty),
314+ // and then the updated value.
315+ n := 0
316+ select {
317+ case <-time.After(coretesting.LongWait):
318+ c.Fatalf("timed out waiting for SetAPIHostPorts to be called")
319+ case servers := <-setter.servers:
320+ if n == 0 {
321+ c.Assert(servers, gc.HasLen, 0)
322+ } else {
323+ c.Assert(servers, gc.DeepEquals, updatedServers)
324+ }
325+ n++
326+ }
327+}

Subscribers

People subscribed via source and target branches

to status/vote changes: