Merge lp:~mfoord/juju-core/ha-rsyslog-api into lp:~go-bot/juju-core/trunk

Proposed by Michael Foord
Status: Superseded
Proposed branch: lp:~mfoord/juju-core/ha-rsyslog-api
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 845 lines (+346/-102)
11 files modified
cmd/jujud/agent.go (+1/-5)
instance/address.go (+7/-0)
state/api/params/params.go (+7/-0)
state/api/rsyslog/rsyslog.go (+51/-6)
state/api/rsyslog/rsyslog_test.go (+57/-13)
state/apiserver/rsyslog/config.go (+33/-0)
state/apiserver/rsyslog/rsyslog.go (+60/-2)
state/apiserver/rsyslog/rsyslog_test.go (+48/-11)
utils/syslog/config.go (+40/-39)
worker/rsyslog/rsyslog_test.go (+24/-8)
worker/rsyslog/worker.go (+18/-18)
To merge this branch: bzr merge lp:~mfoord/juju-core/ha-rsyslog-api
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+219482@code.launchpad.net

This proposal has been superseded by a proposal from 2014-05-19.

Description of the change

utils/syslog: update rsyslog conf

Update rsyslog configuration (and restart)
when the api servers change.

https://codereview.appspot.com/95390044/

To post a comment you must log in.
lp:~mfoord/juju-core/ha-rsyslog-api updated
2731. By Michael Foord

Merge

2732. By Michael Foord

Test fixes - yay

2733. By Michael Foord

Merge plus fixes

2734. By Michael Foord

Expanded test for GetRsyslogConfig

2735. By Michael Foord

Comment fix

2736. By Michael Foord

Test WatchForRsyslogChanges

2737. By Michael Foord

Switch to watching APIHostPorts for RsyslogChanges API

2738. By Michael Foord

Test fixes

2739. By Michael Foord

Change to checking for MachineAgent authorization in the new API

2740. By Michael Foord

Fix build

2741. By Michael Foord

Merge

2742. By Michael Foord

Test fixes

2743. By Michael Foord

Test improvement and comment

2744. By Michael Foord

Merge

2745. By Michael Foord

Merge

2746. By Michael Foord

Remove debugging print

2747. By Michael Foord

Remove testing comments

2748. By Michael Foord

Add back in comments

2749. By Michael Foord

Merge

2750. By Michael Foord

Start using HostPorts in rsyslog template rendering

2751. By Michael Foord

Extract convenience function for building HostPorts

2752. By Michael Foord

Initial test tweaks

2753. By Michael Foord

Merge

Unmerged revisions

2753. By Michael Foord

Merge

2752. By Michael Foord

Initial test tweaks

2751. By Michael Foord

Extract convenience function for building HostPorts

2750. By Michael Foord

Start using HostPorts in rsyslog template rendering

2749. By Michael Foord

Merge

2748. By Michael Foord

Add back in comments

2747. By Michael Foord

Remove testing comments

2746. By Michael Foord

Remove debugging print

2745. By Michael Foord

Merge

2744. By Michael Foord

Merge

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-05-14 21:13:17 +0000
3+++ cmd/jujud/agent.go 2014-05-19 14:05:26 +0000
4@@ -322,11 +322,7 @@
5 var newRsyslogConfigWorker = func(st *apirsyslog.State, agentConfig agent.Config, mode rsyslog.RsyslogMode) (worker.Worker, error) {
6 tag := agentConfig.Tag()
7 namespace := agentConfig.Value(agent.Namespace)
8- addrs, err := agentConfig.APIAddresses()
9- if err != nil {
10- return nil, err
11- }
12- return rsyslog.NewRsyslogConfigWorker(st, mode, tag, namespace, addrs)
13+ return rsyslog.NewRsyslogConfigWorker(st, mode, tag, namespace, []instance.HostPort{})
14 }
15
16 // hookExecutionLock returns an *fslock.Lock suitable for use as a unit
17
18=== modified file 'instance/address.go'
19--- instance/address.go 2014-05-01 00:54:26 +0000
20+++ instance/address.go 2014-05-19 14:05:26 +0000
21@@ -114,6 +114,13 @@
22 return outAddresses
23 }
24
25+//NewHostPorts is a convenience function to create HostPorts from a string
26+//slice and port
27+func NewHostPorts(inAddresses []string, port int) []HostPort {
28+ addresses := NewAddresses(inAddresses...)
29+ return AddressesWithPort(addresses, port)
30+}
31+
32 func DeriveAddressType(value string) AddressType {
33 ip := net.ParseIP(value)
34 switch {
35
36=== modified file 'state/api/params/params.go'
37--- state/api/params/params.go 2014-05-09 13:24:50 +0000
38+++ state/api/params/params.go 2014-05-19 14:05:26 +0000
39@@ -681,6 +681,13 @@
40 CACert []byte
41 }
42
43+// RsyslogConfigResult holds the result of a GetRsyslogConfig call.
44+type RsyslogConfigResult struct {
45+ CACert string
46+ Port int
47+ HostPorts []instance.HostPort
48+}
49+
50 // DistributionGroupResult contains the result of
51 // the DistributionGroup provisioner API call.
52 type DistributionGroupResult struct {
53
54=== modified file 'state/api/rsyslog/rsyslog.go'
55--- state/api/rsyslog/rsyslog.go 2014-04-11 17:51:58 +0000
56+++ state/api/rsyslog/rsyslog.go 2014-05-19 14:05:26 +0000
57@@ -4,25 +4,31 @@
58 package rsyslog
59
60 import (
61+ "fmt"
62+
63+ "launchpad.net/juju-core/instance"
64 "launchpad.net/juju-core/state/api/base"
65- "launchpad.net/juju-core/state/api/common"
66 "launchpad.net/juju-core/state/api/params"
67+ "launchpad.net/juju-core/state/api/watcher"
68 )
69
70 const rsyslogAPI = "Rsyslog"
71
72+// RsyslogConfig holds the values needed for the rsyslog worker
73+type RsyslogConfig struct {
74+ CACert string
75+ Port int
76+ HostPorts []instance.HostPort
77+}
78+
79 // State provides access to the Rsyslog API facade.
80 type State struct {
81- *common.EnvironWatcher
82 caller base.Caller
83 }
84
85 // NewState creates a new client-side Rsyslog facade.
86 func NewState(caller base.Caller) *State {
87- return &State{
88- EnvironWatcher: common.NewEnvironWatcher(rsyslogAPI, caller),
89- caller: caller,
90- }
91+ return &State{caller: caller}
92 }
93
94 // SetRsyslogCert sets the rsyslog CA certificate,
95@@ -42,3 +48,42 @@
96 }
97 return nil
98 }
99+
100+// WatchForRsyslogChanges returns a new NotifyWatcher.
101+func (st *State) WatchForRsyslogChanges(agentTag string) (watcher.NotifyWatcher, error) {
102+ var results params.NotifyWatchResults
103+ args := params.Entities{
104+ Entities: []params.Entity{{Tag: agentTag}},
105+ }
106+
107+ err := st.caller.Call(rsyslogAPI, "", "WatchForRsyslogChanges", args, &results)
108+ if err != nil {
109+ // TODO: Not directly tested
110+ return nil, err
111+ }
112+ if len(results.Results) != 1 {
113+ // TODO: Not directly tested
114+ return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
115+ }
116+ result := results.Results[0]
117+ if result.Error != nil {
118+ // TODO: Not directly tested
119+ return nil, result.Error
120+ }
121+ w := watcher.NewNotifyWatcher(st.caller, result)
122+ return w, nil
123+}
124+
125+// GetRsyslogConfig returns a RsyslogConfig.
126+func (st *State) GetRsyslogConfig() (*RsyslogConfig, error) {
127+ var result params.RsyslogConfigResult
128+ err := st.caller.Call(rsyslogAPI, "", "GetRsyslogConfig", nil, &result)
129+ if err != nil {
130+ return nil, err
131+ }
132+ return &RsyslogConfig{
133+ CACert: result.CACert,
134+ Port: result.Port,
135+ HostPorts: result.HostPorts,
136+ }, nil
137+}
138
139=== modified file 'state/api/rsyslog/rsyslog_test.go'
140--- state/api/rsyslog/rsyslog_test.go 2014-03-21 18:02:23 +0000
141+++ state/api/rsyslog/rsyslog_test.go 2014-05-19 14:05:26 +0000
142@@ -5,14 +5,22 @@
143
144 import (
145 gc "launchpad.net/gocheck"
146+ "launchpad.net/juju-core/instance"
147+ "launchpad.net/juju-core/juju/testing"
148+ "launchpad.net/juju-core/state"
149+ "launchpad.net/juju-core/state/api"
150+ "launchpad.net/juju-core/state/api/rsyslog"
151
152- jujutesting "launchpad.net/juju-core/juju/testing"
153- apitesting "launchpad.net/juju-core/state/api/testing"
154+ statetesting "launchpad.net/juju-core/state/testing"
155+ coretesting "launchpad.net/juju-core/testing"
156 )
157
158 type rsyslogSuite struct {
159- jujutesting.JujuConnSuite
160- *apitesting.EnvironWatcherTests
161+ testing.JujuConnSuite
162+
163+ st *api.State
164+ machine *state.Machine
165+ rsyslog *rsyslog.State
166 }
167
168 var _ = gc.Suite(&rsyslogSuite{})
169@@ -20,15 +28,51 @@
170 func (s *rsyslogSuite) SetUpTest(c *gc.C) {
171 s.JujuConnSuite.SetUpTest(c)
172
173- stateAPI, _ := s.OpenAPIAsNewMachine(c)
174- rsyslogAPI := stateAPI.Rsyslog()
175- c.Assert(rsyslogAPI, gc.NotNil)
176-
177- s.EnvironWatcherTests = apitesting.NewEnvironWatcherTests(
178- rsyslogAPI,
179- s.BackingState,
180- apitesting.NoSecrets,
181- )
182+ s.st, s.machine = s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
183+ err := s.machine.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))
184+ c.Assert(err, gc.IsNil)
185+
186+ // Create the rsyslog API facade
187+ s.rsyslog = s.st.Rsyslog()
188+ c.Assert(s.rsyslog, gc.NotNil)
189+}
190+
191+func (s *rsyslogSuite) TestGetRsyslogConfig(c *gc.C) {
192+ err := s.APIState.Client().EnvironmentSet(map[string]interface{}{"rsyslog-ca-cert": coretesting.CACert})
193+ c.Assert(err, gc.IsNil)
194+
195+ cfg, err := s.rsyslog.GetRsyslogConfig()
196+ c.Assert(err, gc.IsNil)
197+ c.Assert(cfg, gc.NotNil)
198+
199+ c.Assert(cfg.CACert, gc.Equals, coretesting.CACert)
200+ c.Assert(cfg.HostPorts, gc.HasLen, 1)
201+ hostPort := cfg.HostPorts[0]
202+ c.Assert(hostPort.Address.Value, gc.Equals, "0.1.2.3")
203+
204+ // the rsyslog port is set by the provider/dummy/environs.go
205+ c.Assert(hostPort.Port, gc.Equals, 2345)
206+}
207+
208+func (s *rsyslogSuite) TestWatchForRsyslogChanges(c *gc.C) {
209+ w, err := s.rsyslog.WatchForRsyslogChanges(s.machine.Tag())
210+ c.Assert(err, gc.IsNil)
211+ defer statetesting.AssertStop(c, w)
212+
213+ wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w)
214+ // Initial event
215+ wc.AssertOneChange()
216+
217+ // change the API HostPorts
218+ newHostPorts := instance.AddressesWithPort(instance.NewAddresses("127.0.0.1"), 6541)
219+ err = s.State.SetAPIHostPorts([][]instance.HostPort{newHostPorts})
220+ c.Assert(err, gc.IsNil)
221+
222+ // assert we get notified
223+ wc.AssertOneChange()
224+
225+ statetesting.AssertStop(c, w)
226+ wc.AssertClosed()
227 }
228
229 // SetRsyslogCACert is tested in state/apiserver/rsyslog
230
231=== added file 'state/apiserver/rsyslog/config.go'
232--- state/apiserver/rsyslog/config.go 1970-01-01 00:00:00 +0000
233+++ state/apiserver/rsyslog/config.go 2014-05-19 14:05:26 +0000
234@@ -0,0 +1,33 @@
235+package rsyslog
236+
237+import (
238+ "net"
239+
240+ "launchpad.net/juju-core/environs/config"
241+ "launchpad.net/juju-core/instance"
242+ apirsyslog "launchpad.net/juju-core/state/api/rsyslog"
243+)
244+
245+// newRsyslogConfig creates a new instance of the RsyslogConfig.
246+func newRsyslogConfig(envCfg *config.Config, api *RsyslogAPI) (*apirsyslog.RsyslogConfig, error) {
247+ stateAddrsResult, err := api.StateAddresser.StateAddresses()
248+ if err != nil {
249+ return nil, err
250+ }
251+ port := envCfg.SyslogPort()
252+
253+ var bareAddrs []string
254+ for _, addr := range stateAddrsResult.Result {
255+ hostOnly, _, err := net.SplitHostPort(addr)
256+ if err != nil {
257+ return nil, err
258+ }
259+ bareAddrs = append(bareAddrs, hostOnly)
260+ }
261+
262+ return &apirsyslog.RsyslogConfig{
263+ CACert: envCfg.RsyslogCACert(),
264+ Port: port,
265+ HostPorts: instance.NewHostPorts(bareAddrs, port),
266+ }, nil
267+}
268
269=== modified file 'state/apiserver/rsyslog/rsyslog.go'
270--- state/apiserver/rsyslog/rsyslog.go 2014-04-11 17:51:58 +0000
271+++ state/apiserver/rsyslog/rsyslog.go 2014-05-19 14:05:26 +0000
272@@ -8,17 +8,25 @@
273 "launchpad.net/juju-core/state"
274 "launchpad.net/juju-core/state/api/params"
275 "launchpad.net/juju-core/state/apiserver/common"
276+ "launchpad.net/juju-core/state/watcher"
277 )
278
279 // RsyslogAPI implements the API used by the rsyslog worker.
280 type RsyslogAPI struct {
281 *common.EnvironWatcher
282- st *state.State
283- canModify bool
284+
285+ st *state.State
286+ resources *common.Resources
287+ authorizer common.Authorizer
288+ StateAddresser *common.StateAddresser
289+ canModify bool
290 }
291
292 // NewRsyslogAPI creates a new instance of the Rsyslog API.
293 func NewRsyslogAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*RsyslogAPI, error) {
294+ if !authorizer.AuthMachineAgent() && !authorizer.AuthUnitAgent() {
295+ return nil, common.ErrPerm
296+ }
297 // Can always watch for environ changes.
298 getCanWatch := common.AuthAlways(true)
299 // Does not get the secrets.
300@@ -26,10 +34,14 @@
301 return &RsyslogAPI{
302 EnvironWatcher: common.NewEnvironWatcher(st, resources, getCanWatch, getCanReadSecrets),
303 st: st,
304+ authorizer: authorizer,
305+ resources: resources,
306 canModify: authorizer.AuthEnvironManager(),
307+ StateAddresser: common.NewStateAddresser(st),
308 }, nil
309 }
310
311+// SetRsyslogCert sets the rsyslog CACert.
312 func (api *RsyslogAPI) SetRsyslogCert(args params.SetRsyslogCertParams) (params.ErrorResult, error) {
313 var result params.ErrorResult
314 if !api.canModify {
315@@ -46,3 +58,49 @@
316 }
317 return result, nil
318 }
319+
320+// GetRsyslogConfig returns a RsyslogConfigResult.
321+func (api *RsyslogAPI) GetRsyslogConfig() (params.RsyslogConfigResult, error) {
322+ cfg, err := api.st.EnvironConfig()
323+ if err != nil {
324+ return params.RsyslogConfigResult{}, err
325+ }
326+
327+ rsyslogCfg, err := newRsyslogConfig(cfg, api)
328+ if err != nil {
329+ return params.RsyslogConfigResult{}, err
330+ }
331+
332+ return params.RsyslogConfigResult{
333+ CACert: rsyslogCfg.CACert,
334+ Port: rsyslogCfg.Port,
335+ HostPorts: rsyslogCfg.HostPorts,
336+ }, nil
337+}
338+
339+// WatchForRsyslogChanges starts a watcher to track if there are changes
340+// that require we update the rsyslog.d configurations for a machine and/or unit.
341+func (api *RsyslogAPI) WatchForRsyslogChanges(args params.Entities) (params.NotifyWatchResults, error) {
342+ result := params.NotifyWatchResults{
343+ Results: make([]params.NotifyWatchResult, len(args.Entities)),
344+ }
345+ for i := range args.Entities {
346+ err := common.ErrPerm
347+ if api.authorizer.AuthMachineAgent() || api.authorizer.AuthUnitAgent() {
348+ watch := api.st.WatchAPIHostPorts()
349+ // Consume the initial event. Technically, API
350+ // calls to Watch 'transmit' the initial event
351+ // in the Watch response. But NotifyWatchers
352+ // have no state to transmit.
353+ if _, ok := <-watch.Changes(); ok {
354+ result.Results[i].NotifyWatcherId = api.resources.Register(watch)
355+ err = nil
356+ } else {
357+ err = watcher.MustErr(watch)
358+ }
359+ }
360+ result.Results[i].Error = common.ServerError(err)
361+ }
362+ return result, nil
363+
364+}
365
366=== modified file 'state/apiserver/rsyslog/rsyslog_test.go'
367--- state/apiserver/rsyslog/rsyslog_test.go 2014-04-11 17:51:58 +0000
368+++ state/apiserver/rsyslog/rsyslog_test.go 2014-05-19 14:05:26 +0000
369@@ -9,6 +9,7 @@
370 jc "github.com/juju/testing/checkers"
371 gc "launchpad.net/gocheck"
372
373+ "launchpad.net/juju-core/instance"
374 "launchpad.net/juju-core/juju/testing"
375 "launchpad.net/juju-core/state"
376 "launchpad.net/juju-core/state/api/params"
377@@ -25,6 +26,7 @@
378 *commontesting.EnvironWatcherTest
379 authorizer apiservertesting.FakeAuthorizer
380 resources *common.Resources
381+ rsyslog *rsyslog.RsyslogAPI
382 }
383
384 var _ = gc.Suite(&rsyslogSuite{})
385@@ -34,6 +36,7 @@
386 s.authorizer = apiservertesting.FakeAuthorizer{
387 LoggedIn: true,
388 EnvironManager: true,
389+ MachineAgent: true,
390 }
391 s.resources = common.NewResources()
392 api, err := rsyslog.NewRsyslogAPI(s.State, s.resources, s.authorizer)
393@@ -43,28 +46,37 @@
394 }
395
396 func verifyRsyslogCACert(c *gc.C, st *apirsyslog.State, expected string) {
397- cfg, err := st.EnvironConfig()
398+ cfg, err := st.GetRsyslogConfig()
399 c.Assert(err, gc.IsNil)
400- c.Assert(cfg.RsyslogCACert(), gc.DeepEquals, expected)
401+ c.Assert(cfg.CACert, gc.DeepEquals, expected)
402 }
403
404 func (s *rsyslogSuite) TestSetRsyslogCert(c *gc.C) {
405- st, _ := s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
406- err := st.Rsyslog().SetRsyslogCert(coretesting.CACert)
407+ st, m := s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
408+ err := m.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))
409+ c.Assert(err, gc.IsNil)
410+
411+ err = st.Rsyslog().SetRsyslogCert(coretesting.CACert)
412 c.Assert(err, gc.IsNil)
413 verifyRsyslogCACert(c, st.Rsyslog(), coretesting.CACert)
414 }
415
416 func (s *rsyslogSuite) TestSetRsyslogCertNil(c *gc.C) {
417- st, _ := s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
418- err := st.Rsyslog().SetRsyslogCert("")
419+ st, m := s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
420+ err := m.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))
421+ c.Assert(err, gc.IsNil)
422+
423+ err = st.Rsyslog().SetRsyslogCert("")
424 c.Assert(err, gc.ErrorMatches, "no certificates found")
425 verifyRsyslogCACert(c, st.Rsyslog(), "")
426 }
427
428 func (s *rsyslogSuite) TestSetRsyslogCertInvalid(c *gc.C) {
429- st, _ := s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
430- err := st.Rsyslog().SetRsyslogCert(string(pem.EncodeToMemory(&pem.Block{
431+ st, m := s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
432+ err := m.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))
433+ c.Assert(err, gc.IsNil)
434+
435+ err = st.Rsyslog().SetRsyslogCert(string(pem.EncodeToMemory(&pem.Block{
436 Type: "CERTIFICATE",
437 Bytes: []byte("not a valid certificate"),
438 })))
439@@ -73,10 +85,35 @@
440 }
441
442 func (s *rsyslogSuite) TestSetRsyslogCertPerms(c *gc.C) {
443- st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits)
444- err := st.Rsyslog().SetRsyslogCert(coretesting.CACert)
445+ // create a machine-0 so we have an addresss to log to
446+ m, err := s.State.AddMachine("trusty", state.JobManageEnviron)
447+ c.Assert(err, gc.IsNil)
448+ err = m.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))
449+ c.Assert(err, gc.IsNil)
450+
451+ unitState, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits)
452+ err = unitState.Rsyslog().SetRsyslogCert(coretesting.CACert)
453 c.Assert(err, gc.ErrorMatches, "invalid entity name or password")
454 c.Assert(err, jc.Satisfies, params.IsCodeUnauthorized)
455 // Verify no change was effected.
456- verifyRsyslogCACert(c, st.Rsyslog(), "")
457+ verifyRsyslogCACert(c, unitState.Rsyslog(), "")
458+}
459+
460+func (s *rsyslogSuite) TestUpgraderAPIAllowsUnitAgent(c *gc.C) {
461+ anAuthorizer := s.authorizer
462+ anAuthorizer.UnitAgent = true
463+ anAuthorizer.MachineAgent = false
464+ anUpgrader, err := rsyslog.NewRsyslogAPI(s.State, s.resources, anAuthorizer)
465+ c.Check(err, gc.IsNil)
466+ c.Check(anUpgrader, gc.NotNil)
467+}
468+
469+func (s *rsyslogSuite) TestUpgraderAPIRefusesNonUnitNonMachineAgent(c *gc.C) {
470+ anAuthorizer := s.authorizer
471+ anAuthorizer.UnitAgent = false
472+ anAuthorizer.MachineAgent = false
473+ anUpgrader, err := rsyslog.NewRsyslogAPI(s.State, s.resources, anAuthorizer)
474+ c.Check(err, gc.NotNil)
475+ c.Check(anUpgrader, gc.IsNil)
476+ c.Assert(err, gc.ErrorMatches, "permission denied")
477 }
478
479=== modified file 'utils/syslog/config.go'
480--- utils/syslog/config.go 2014-05-12 10:28:29 +0000
481+++ utils/syslog/config.go 2014-05-19 14:05:26 +0000
482@@ -8,8 +8,9 @@
483 "fmt"
484 "io/ioutil"
485 "path/filepath"
486- "strings"
487 "text/template"
488+
489+ "launchpad.net/juju-core/instance"
490 )
491
492 // tagOffset represents the substring start value for the tag to return
493@@ -53,8 +54,8 @@
494 $template LongTagForwardFormat,"<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg%"
495
496 $RuleSet local
497-{{range $i, $stateServerIP := stateServerHosts}}
498-# start: Forwarding rule for {{$stateServerIP}}
499+{{range $i, $rsyslogServer := rsyslogServers}}
500+# start: Forwarding rule for {{$rsyslogServer}}
501 $ActionQueueType LinkedList
502 $ActionQueueFileName {{logfileName}}{{namespace}}_{{$i}}
503 $ActionResumeRetryCount -1
504@@ -64,8 +65,8 @@
505 $ActionSendStreamDriverAuthMode anon
506 $ActionSendStreamDriverMode 1 # run driver in TLS-only mode
507
508-:syslogtag, startswith, "juju{{namespace}}-" @@{{$stateServerIP}}:{{portNumber}};LongTagForwardFormat
509-# end: Forwarding rule for {{$stateServerIP}}
510+:syslogtag, startswith, "juju{{namespace}}-" @@{{$rsyslogServer}};LongTagForwardFormat
511+# end: Forwarding rule for {{rsyslogServer}}
512 {{end}}
513 & ~
514 $FileCreateMode 0640
515@@ -112,8 +113,8 @@
516 $InputFileTag juju{{namespace}}-{{logfileName}}:
517 $InputFileStateFile {{logfileName}}{{namespace}}
518 $InputRunFileMonitor
519-{{range $i, $stateServerIP := stateServerHosts}}
520-# start: Forwarding rule for {{$stateServerIP}}
521+{{range $i, $rsyslogServer := rsyslogServers}}
522+# start: Forwarding rule for {{$rsyslogServer}}
523 $ActionQueueType LinkedList
524 $ActionQueueFileName {{logfileName}}{{namespace}}_{{$i}}
525 $ActionResumeRetryCount -1
526@@ -124,8 +125,8 @@
527 $ActionSendStreamDriverMode 1 # run driver in TLS-only mode
528
529 $template LongTagForwardFormat,"<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg%"
530-:syslogtag, startswith, "juju{{namespace}}-" @@{{$stateServerIP}}:{{portNumber}};LongTagForwardFormat
531-# end: Forwarding rule for {{$stateServerIP}}
532+:syslogtag, startswith, "juju{{namespace}}-" @@{{$rsyslogServer}};LongTagForwardFormat
533+# end: Forwarding rule for {{$rsyslogServer}}
534 {{end}}
535 & ~
536 `
537@@ -159,8 +160,8 @@
538 ConfigFileName string
539 // the name of the log file to tail.
540 LogFileName string
541- // the addresses of the state server to which messages should be forwarded.
542- StateServerAddresses []string
543+ // the addresses of the rsyslog servers to which messages should be forwarded.
544+ RsyslogHostPorts []instance.HostPort
545 // CA certificate file name.
546 CACertFileName string
547 // Server certificate file name.
548@@ -177,13 +178,13 @@
549
550 // NewForwardConfig creates a SyslogConfig instance used on unit nodes to forward log entries
551 // to the state server nodes.
552-func NewForwardConfig(logFile, logDir string, port int, namespace string, stateServerAddresses []string) *SyslogConfig {
553+func NewForwardConfig(logFile, logDir string, port int, namespace string, rsyslogHostPorts []instance.HostPort) *SyslogConfig {
554 conf := &SyslogConfig{
555- configTemplate: nodeRsyslogTemplate,
556- StateServerAddresses: stateServerAddresses,
557- LogFileName: logFile,
558- Port: port,
559- LogDir: logDir,
560+ configTemplate: nodeRsyslogTemplate,
561+ RsyslogHostPorts: rsyslogHostPorts,
562+ LogFileName: logFile,
563+ Port: port,
564+ LogDir: logDir,
565 }
566 if namespace != "" {
567 conf.Namespace = "-" + namespace
568@@ -193,13 +194,13 @@
569
570 // NewAccumulateConfig creates a SyslogConfig instance used to accumulate log entries from the
571 // various unit nodes.
572-func NewAccumulateConfig(logFile, logDir string, port int, namespace string, stateServerAddresses []string) *SyslogConfig {
573+func NewAccumulateConfig(logFile, logDir string, port int, namespace string, rsyslogHostPorts []instance.HostPort) *SyslogConfig {
574 conf := &SyslogConfig{
575- configTemplate: stateServerRsyslogTemplate,
576- LogFileName: logFile,
577- Port: port,
578- LogDir: logDir,
579- StateServerAddresses: stateServerAddresses,
580+ configTemplate: stateServerRsyslogTemplate,
581+ LogFileName: logFile,
582+ Port: port,
583+ LogDir: logDir,
584+ RsyslogHostPorts: rsyslogHostPorts,
585 }
586 if namespace != "" {
587 conf.Namespace = "-" + namespace
588@@ -236,13 +237,13 @@
589
590 // Render generates the rsyslog config.
591 func (slConfig *SyslogConfig) Render() ([]byte, error) {
592- var stateServerHosts = func() []string {
593- var hosts []string
594- for _, addr := range slConfig.StateServerAddresses {
595- parts := strings.Split(addr, ":")
596- hosts = append(hosts, parts[0])
597+ var rsyslogServers = func() []string {
598+ var servers []string
599+ for _, hostPort := range slConfig.RsyslogHostPorts {
600+ server := hostPort.Address.Value + ":" + string(hostPort.Port)
601+ servers = append(servers, server)
602 }
603- return hosts
604+ return servers
605 }
606
607 var logFilePath = func() string {
608@@ -251,16 +252,16 @@
609
610 t := template.New("")
611 t.Funcs(template.FuncMap{
612- "logfileName": func() string { return slConfig.LogFileName },
613- "stateServerHosts": stateServerHosts,
614- "logfilePath": logFilePath,
615- "portNumber": func() int { return slConfig.Port },
616- "logDir": func() string { return slConfig.LogDir },
617- "namespace": func() string { return slConfig.Namespace },
618- "tagStart": func() int { return tagOffset + len(slConfig.Namespace) },
619- "tlsCACertPath": slConfig.CACertPath,
620- "tlsCertPath": slConfig.ServerCertPath,
621- "tlsKeyPath": slConfig.ServerKeyPath,
622+ "logfileName": func() string { return slConfig.LogFileName },
623+ "rsyslogServers": rsyslogServers,
624+ "logfilePath": logFilePath,
625+ "portNumber": func() int { return slConfig.Port },
626+ "logDir": func() string { return slConfig.LogDir },
627+ "namespace": func() string { return slConfig.Namespace },
628+ "tagStart": func() int { return tagOffset + len(slConfig.Namespace) },
629+ "tlsCACertPath": slConfig.CACertPath,
630+ "tlsCertPath": slConfig.ServerCertPath,
631+ "tlsKeyPath": slConfig.ServerKeyPath,
632 })
633
634 // Process the rsyslog config template and echo to the conf file.
635
636=== modified file 'worker/rsyslog/rsyslog_test.go'
637--- worker/rsyslog/rsyslog_test.go 2014-05-12 15:57:30 +0000
638+++ worker/rsyslog/rsyslog_test.go 2014-05-19 14:05:26 +0000
639@@ -16,6 +16,7 @@
640 gc "launchpad.net/gocheck"
641
642 "launchpad.net/juju-core/cert"
643+ "launchpad.net/juju-core/instance"
644 jujutesting "launchpad.net/juju-core/juju/testing"
645 "launchpad.net/juju-core/state"
646 "launchpad.net/juju-core/state/api"
647@@ -30,6 +31,9 @@
648
649 type RsyslogSuite struct {
650 jujutesting.JujuConnSuite
651+
652+ st *api.State
653+ machine *state.Machine
654 }
655
656 var _ = gc.Suite(&RsyslogSuite{})
657@@ -50,6 +54,10 @@
658 s.PatchValue(rsyslog.RestartRsyslog, func() error { return nil })
659 s.PatchValue(rsyslog.LogDir, c.MkDir())
660 s.PatchValue(rsyslog.RsyslogConfDir, c.MkDir())
661+
662+ s.st, s.machine = s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
663+ err := s.machine.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))
664+ c.Assert(err, gc.IsNil)
665 }
666
667 func waitForFile(c *gc.C, file string) {
668@@ -87,7 +95,7 @@
669 }
670
671 func (s *RsyslogSuite) TestTearDown(c *gc.C) {
672- st, m := s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
673+ st, m := s.st, s.machine
674 worker, err := rsyslog.NewRsyslogConfigWorker(st.Rsyslog(), rsyslog.RsyslogModeAccumulate, m.Tag(), "", []string{"0.1.2.3"})
675 c.Assert(err, gc.IsNil)
676 confFile := filepath.Join(*rsyslog.RsyslogConfDir, "25-juju.conf")
677@@ -131,7 +139,7 @@
678 }
679
680 func (s *RsyslogSuite) TestModeAccumulate(c *gc.C) {
681- st, m := s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
682+ st, m := s.st, s.machine
683 worker, err := rsyslog.NewRsyslogConfigWorker(st.Rsyslog(), rsyslog.RsyslogModeAccumulate, m.Tag(), "", nil)
684 c.Assert(err, gc.IsNil)
685 defer func() { c.Assert(worker.Wait(), gc.IsNil) }()
686@@ -165,7 +173,7 @@
687 }
688
689 func (s *RsyslogSuite) TestAccumulateHA(c *gc.C) {
690- _, m := s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
691+ m := s.machine
692 syslogConfig := syslog.NewAccumulateConfig(m.Tag(), *rsyslog.LogDir, 6541, "", []string{"192.168.1", "127.0.0.1"})
693 rendered, err := syslogConfig.Render()
694 c.Assert(err, gc.IsNil)
695@@ -178,7 +186,11 @@
696 }
697
698 func (s *RsyslogSuite) TestNamespace(c *gc.C) {
699- st, _ := s.OpenAPIAsNewMachine(c, state.JobManageEnviron)
700+ st := s.st
701+ // set the rsyslog cert
702+ err := s.APIState.Client().EnvironmentSet(map[string]interface{}{"rsyslog-ca-cert": coretesting.CACert})
703+ c.Assert(err, gc.IsNil)
704+
705 // namespace only takes effect in filenames
706 // for machine-0; all others assume isolation.
707 s.testNamespace(c, st, "machine-0", "", "25-juju.conf", *rsyslog.LogDir)
708@@ -201,19 +213,23 @@
709
710 err := os.MkdirAll(expectedLogDir, 0755)
711 c.Assert(err, gc.IsNil)
712- err = s.APIState.Client().EnvironmentSet(map[string]interface{}{"rsyslog-ca-cert": coretesting.CACert})
713- c.Assert(err, gc.IsNil)
714 worker, err := rsyslog.NewRsyslogConfigWorker(st.Rsyslog(), rsyslog.RsyslogModeForwarding, tag, namespace, []string{"0.1.2.3"})
715 c.Assert(err, gc.IsNil)
716 defer func() { c.Assert(worker.Wait(), gc.IsNil) }()
717 defer worker.Kill()
718
719- // Ensure that ca-cert.pem gets written to the expected log dir.
720- waitForFile(c, filepath.Join(expectedLogDir, "ca-cert.pem"))
721+ // change the API HostPorts to trigger an rsyslog restart
722+ newHostPorts := instance.AddressesWithPort(instance.NewAddresses("127.0.0.1"), 6541)
723+ err = s.State.SetAPIHostPorts([][]instance.HostPort{newHostPorts})
724+ c.Assert(err, gc.IsNil)
725
726 // Wait for rsyslog to be restarted, so we can check to see
727 // what the name of the config file is.
728 waitForRestart(c, restarted)
729+
730+ // Ensure that ca-cert.pem gets written to the expected log dir.
731+ waitForFile(c, filepath.Join(expectedLogDir, "ca-cert.pem"))
732+
733 dir, err := os.Open(*rsyslog.RsyslogConfDir)
734 c.Assert(err, gc.IsNil)
735 names, err := dir.Readdirnames(-1)
736
737=== modified file 'worker/rsyslog/worker.go'
738--- worker/rsyslog/worker.go 2014-05-14 21:13:17 +0000
739+++ worker/rsyslog/worker.go 2014-05-19 14:05:26 +0000
740@@ -15,6 +15,7 @@
741
742 "launchpad.net/juju-core/agent"
743 "launchpad.net/juju-core/cert"
744+ "launchpad.net/juju-core/instance"
745 "launchpad.net/juju-core/names"
746 apirsyslog "launchpad.net/juju-core/state/api/rsyslog"
747 "launchpad.net/juju-core/state/api/watcher"
748@@ -53,7 +54,7 @@
749 mode RsyslogMode
750 syslogConfig *syslog.SyslogConfig
751 rsyslogConfPath string
752-
753+ tag string
754 // We store the syslog-port and rsyslog-ca-cert
755 // values after writing the rsyslog configuration,
756 // so we can decide whether a change has occurred.
757@@ -63,12 +64,12 @@
758
759 var _ worker.NotifyWatchHandler = (*RsyslogConfigHandler)(nil)
760
761-// NewRsyslogConfigWorker returns a worker.Worker that watches
762-// for config changes and updates rsyslog configuration based
763+// NewRsyslogConfigWorker returns a worker.Worker that uses
764+// WatchForRsyslogChanges and updates rsyslog configuration based
765 // on changes. The worker will remove the configuration file
766 // on teardown.
767-func NewRsyslogConfigWorker(st *apirsyslog.State, mode RsyslogMode, tag, namespace string, stateServerAddrs []string) (worker.Worker, error) {
768- handler, err := newRsyslogConfigHandler(st, mode, tag, namespace, stateServerAddrs)
769+func NewRsyslogConfigWorker(st *apirsyslog.State, mode RsyslogMode, tag, namespace string, rsyslogHostPorts []instance.HostPort) (worker.Worker, error) {
770+ handler, err := newRsyslogConfigHandler(st, mode, tag, namespace, rsyslogHostPorts)
771 if err != nil {
772 return nil, err
773 }
774@@ -76,15 +77,15 @@
775 return worker.NewNotifyWorker(handler), nil
776 }
777
778-func newRsyslogConfigHandler(st *apirsyslog.State, mode RsyslogMode, tag, namespace string, stateServerAddrs []string) (*RsyslogConfigHandler, error) {
779+func newRsyslogConfigHandler(st *apirsyslog.State, mode RsyslogMode, tag, namespace string, rsyslogHostPorts []instance.HostPort) (*RsyslogConfigHandler, error) {
780 var syslogConfig *syslog.SyslogConfig
781 if mode == RsyslogModeAccumulate {
782 syslogConfig = syslog.NewAccumulateConfig(
783- tag, logDir, 0, namespace, stateServerAddrs,
784+ tag, logDir, 0, namespace, rsyslogHostPorts,
785 )
786 } else {
787 syslogConfig = syslog.NewForwardConfig(
788- tag, logDir, 0, namespace, stateServerAddrs,
789+ tag, logDir, 0, namespace, rsyslogHostPorts,
790 )
791 }
792
793@@ -116,6 +117,7 @@
794 st: st,
795 mode: mode,
796 syslogConfig: syslogConfig,
797+ tag: tag,
798 }, nil
799 }
800
801@@ -125,7 +127,7 @@
802 return nil, errors.Annotate(err, "failed to write rsyslog certificates")
803 }
804 }
805- return h.st.WatchForEnvironConfigChanges()
806+ return h.st.WatchForRsyslogChanges(h.tag)
807 }
808
809 var restartRsyslog = syslog.Restart
810@@ -138,20 +140,18 @@
811 }
812
813 func (h *RsyslogConfigHandler) Handle() error {
814- cfg, err := h.st.EnvironConfig()
815+ cfg, err := h.st.GetRsyslogConfig()
816 if err != nil {
817 return errors.Annotate(err, "cannot get environ config")
818 }
819- rsyslogCACert := cfg.RsyslogCACert()
820+ rsyslogCACert := cfg.CACert
821 if rsyslogCACert == "" {
822 return nil
823 }
824- // If neither syslog-port nor rsyslog-ca-cert
825- // have changed, we can drop out now.
826- if cfg.SyslogPort() == h.syslogPort && rsyslogCACert == h.rsyslogCACert {
827- return nil
828- }
829- h.syslogConfig.Port = cfg.SyslogPort()
830+
831+ h.syslogConfig.Port = cfg.Port
832+ h.syslogConfig.RsyslogHostPorts = cfg.HostPorts
833+
834 if h.mode == RsyslogModeForwarding {
835 if err := writeFileAtomic(h.syslogConfig.CACertPath(), []byte(rsyslogCACert), 0644, 0, 0); err != nil {
836 return errors.Annotate(err, "cannot write CA certificate")
837@@ -172,7 +172,7 @@
838 // Record config values so we don't try again.
839 // Do this last so we recover from intermittent
840 // failures.
841- h.syslogPort = cfg.SyslogPort()
842+ h.syslogPort = cfg.Port
843 h.rsyslogCACert = rsyslogCACert
844 return nil
845 }

Subscribers

People subscribed via source and target branches

to status/vote changes: