Merge lp:~jameinel/juju-core/api-registry-tracks-type into lp:~go-bot/juju-core/trunk

Proposed by John A Meinel
Status: Work in progress
Proposed branch: lp:~jameinel/juju-core/api-registry-tracks-type
Merge into: lp:~go-bot/juju-core/trunk
Prerequisite: lp:~jameinel/juju-core/api-use-register-standard-facade
Diff against target: 384 lines (+98/-70)
7 files modified
state/apiserver/common/export_test.go (+13/-0)
state/apiserver/common/registry.go (+33/-12)
state/apiserver/common/registry_test.go (+29/-42)
state/apiserver/root.go (+1/-1)
state/apiserver/usermanager/usermanager.go (+2/-9)
state/apiserver/usermanager/usermanager_test.go (+2/-2)
state/apiserver/watcher.go (+18/-4)
To merge this branch: bzr merge lp:~jameinel/juju-core/api-registry-tracks-type
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+220588@code.launchpad.net

Description of the change

state/apiserver/common: Registry tracks types

This changes the Facades registry so that instead of just tracking the
FacadeFactory functions, it also explicitly tracks the Facade type
itself. The main benefit from doing this is that we have a proper (and
passing) TestDiscardedAPIMethods that allows us to introspect everything
we are exposing over the API without having to actually instantiate any
of those objects.

While the only specific win today is the test case, the wins for the
longer term are:

1) The ability to walk the whole API and determine all Facade versions
along with all methods that are available.

2) If we so choose, we can restore the "introspect a Root object"
(rpc.Serve vs the new rpc.ServeCaller) and have it go back to doing
exactly what it did with hardcoded types per exposed facade. That was
more code right now, which meant delaying getting API versioning out
there.

3) It helps enforce the norm that (Facade, version) describes exactly 1
type, so we don't accidently do weird things and return variable APIs
based on the "id" of requests.

I don't yet have code that ensures the objects being returned by the
factory exactly match the Type that they've been registered with. It
didn't seem to be a big win given that most places use
RegisterStandardFacade that explicitly does the registration by
inferring the type from the function that is handed in.

However, "RegisterFacade(Factory, Type)" does define Factory as
returning interface{} and Type as whatever you want. So if we want a bit
more rigidity, we could add that here.

https://codereview.appspot.com/97630045/

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote :

Reviewers: mp+220588_code.launchpad.net,

Message:
Please take a look.

Description:
state/apiserver/common: Registry tracks types

This changes the Facades registry so that instead of just tracking the
FacadeFactory functions, it also explicitly tracks the Facade type
itself. The main benefit from doing this is that we have a proper (and
passing) TestDiscardedAPIMethods that allows us to introspect everything
we are exposing over the API without having to actually instantiate any
of those objects.

While the only specific win today is the test case, the wins for the
longer term are:

1) The ability to walk the whole API and determine all Facade versions
along with all methods that are available.

2) If we so choose, we can restore the "introspect a Root object"
(rpc.Serve vs the new rpc.ServeCaller) and have it go back to doing
exactly what it did with hardcoded types per exposed facade. That was
more code right now, which meant delaying getting API versioning out
there.

3) It helps enforce the norm that (Facade, version) describes exactly 1
type, so we don't accidently do weird things and return variable APIs
based on the "id" of requests.

I don't yet have code that ensures the objects being returned by the
factory exactly match the Type that they've been registered with. It
didn't seem to be a big win given that most places use
RegisterStandardFacade that explicitly does the registration by
inferring the type from the function that is handed in.

However, "RegisterFacade(Factory, Type)" does define Factory as
returning interface{} and Type as whatever you want. So if we want a bit
more rigidity, we could add that here.

https://code.launchpad.net/~jameinel/juju-core/api-registry-tracks-type/+merge/220588

Requires:
https://code.launchpad.net/~jameinel/juju-core/api-use-register-standard-facade/+merge/219670

(do not edit description out of merge proposal)

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

Affected files (+102, -72 lines):
   A [revision details]
   M state/apiserver/common/export_test.go
   M state/apiserver/common/registry.go
   M state/apiserver/common/registry_test.go
   M state/apiserver/root.go
   M state/apiserver/upgrader/upgrader.go
   M state/apiserver/usermanager/usermanager.go
   M state/apiserver/usermanager/usermanager_test.go
   M state/apiserver/watcher.go

Revision history for this message
Dimiter Naydenov (dimitern) wrote :

LGTM with a few minor formatting suggestions, otherwise the code looks
fine.

https://codereview.appspot.com/97630045/diff/1/state/apiserver/common/registry_test.go
File state/apiserver/common/registry_test.go (left):

https://codereview.appspot.com/97630045/diff/1/state/apiserver/common/registry_test.go#oldcode196
state/apiserver/common/registry_test.go:196: // We use a FakeAuthorizer
that says it is allowed to do everything, so
How come we don't need the authorizer anymore?

https://codereview.appspot.com/97630045/diff/1/state/apiserver/common/registry_test.go
File state/apiserver/common/registry_test.go (right):

https://codereview.appspot.com/97630045/diff/1/state/apiserver/common/registry_test.go#newcode42
state/apiserver/common/registry_test.go:42:
common.RegisterFacade("myfacade", 0, testFacade,
The indentation here looks a bit weird, how about:

common.RegisterFacade(
     "myfacade", 0, testFacade,
     reflect.TypeOf(&v).Elem(),
)

It's more of a personal preference (esp. the comma before the last
closing parenthesis). This applies to all similar cases below, if you
decide to do it.

https://codereview.appspot.com/97630045/diff/1/state/apiserver/upgrader/upgrader.go
File state/apiserver/upgrader/upgrader.go (right):

https://codereview.appspot.com/97630045/diff/1/state/apiserver/upgrader/upgrader.go#newcode24
state/apiserver/upgrader/upgrader.go:24:
common.RegisterFacade("Upgrader", 0, upgraderFacade,
Indentation here, as well (see previous comment).

https://codereview.appspot.com/97630045/diff/1/state/apiserver/watcher.go
File state/apiserver/watcher.go (right):

https://codereview.appspot.com/97630045/diff/1/state/apiserver/watcher.go#newcode16
state/apiserver/watcher.go:16: common.RegisterFacade(
See - it looks better like it is here.

https://codereview.appspot.com/97630045/

2753. By John A Meinel

reformat according to review feedback.

Revision history for this message
John A Meinel (jameinel) wrote :

Please take a look.

https://codereview.appspot.com/97630045/diff/1/state/apiserver/common/registry_test.go
File state/apiserver/common/registry_test.go (left):

https://codereview.appspot.com/97630045/diff/1/state/apiserver/common/registry_test.go#oldcode196
state/apiserver/common/registry_test.go:196: // We use a FakeAuthorizer
that says it is allowed to do everything, so
On 2014/05/22 10:24:00, dimitern wrote:
> How come we don't need the authorizer anymore?

We are now inspecting the registered Types rather than actually
instantiating an object and inspecting it.
You need an Authorizor for objects to actually be created (because most
of the NewKeyManager style functions actually check the Authorizer
before they return anything.)

This also had the bug that the inspection *just didn't work* for the
Watcher APIs because those have to have a concrete watcher already
registered with a given Id.

So this gets around the problem by tracking the types in the registry,
so that we can inspect what APIs they make available without having to
actually instantiate those objects.

https://codereview.appspot.com/97630045/diff/1/state/apiserver/common/registry_test.go
File state/apiserver/common/registry_test.go (right):

https://codereview.appspot.com/97630045/diff/1/state/apiserver/common/registry_test.go#newcode42
state/apiserver/common/registry_test.go:42:
common.RegisterFacade("myfacade", 0, testFacade,
On 2014/05/22 10:24:00, dimitern wrote:
> The indentation here looks a bit weird, how about:

> common.RegisterFacade(
> "myfacade", 0, testFacade,
> reflect.TypeOf(&v).Elem(),
> )

> It's more of a personal preference (esp. the comma before the last
closing
> parenthesis). This applies to all similar cases below, if you decide
to do it.

So it turns out the line length wasn't very long, so I just wrapped all
of them back up into one line. But I'll keep it in mind in the future.

https://codereview.appspot.com/97630045/diff/1/state/apiserver/upgrader/upgrader.go
File state/apiserver/upgrader/upgrader.go (right):

https://codereview.appspot.com/97630045/diff/1/state/apiserver/upgrader/upgrader.go#newcode24
state/apiserver/upgrader/upgrader.go:24:
common.RegisterFacade("Upgrader", 0, upgraderFacade,
On 2014/05/22 10:24:00, dimitern wrote:
> Indentation here, as well (see previous comment).

Done.

https://codereview.appspot.com/97630045/diff/1/state/apiserver/watcher.go
File state/apiserver/watcher.go (right):

https://codereview.appspot.com/97630045/diff/1/state/apiserver/watcher.go#newcode16
state/apiserver/watcher.go:16: common.RegisterFacade(
On 2014/05/22 10:24:00, dimitern wrote:
> See - it looks better like it is here.

Done.

https://codereview.appspot.com/97630045/

2754. By John A Meinel

Merge up the removal of all of the compat functions.

2755. By John A Meinel

Merged api-use-register-standard-facade into api-registry-tracks-type.

2756. By John A Meinel

Merged api-use-register-standard-facade into api-registry-tracks-type.

2757. By John A Meinel

Merge up the api-use-register-standard-facade to bring in the fixes for Upgrader

2758. By John A Meinel

when merging up we accidentally left 'reflect' import around

Unmerged revisions

2758. By John A Meinel

when merging up we accidentally left 'reflect' import around

2757. By John A Meinel

Merge up the api-use-register-standard-facade to bring in the fixes for Upgrader

2756. By John A Meinel

Merged api-use-register-standard-facade into api-registry-tracks-type.

2755. By John A Meinel

Merged api-use-register-standard-facade into api-registry-tracks-type.

2754. By John A Meinel

Merge up the removal of all of the compat functions.

2753. By John A Meinel

reformat according to review feedback.

2752. By John A Meinel

fix a changed function name

2751. By John A Meinel

Merge api-use-register-standard-facade.

2750. By John A Meinel

Merged api-use-register-standard-facade into api-registry-tracks-type.

2749. By John A Meinel

Now that we have GetFacadeType we can properly test everything is exposed correctly.

We still have to sort out Client and Pinger, but the test suite passes now.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'state/apiserver/common/export_test.go'
2--- state/apiserver/common/export_test.go 2014-05-26 10:02:18 +0000
3+++ state/apiserver/common/export_test.go 2014-05-26 10:02:19 +0000
4@@ -3,7 +3,20 @@
5
6 package common
7
8+import (
9+ "launchpad.net/juju-core/utils/registry"
10+)
11+
12 var (
13 ValidateNewFacade = validateNewFacade
14 WrapNewFacade = wrapNewFacade
15 )
16+
17+type Patcher interface {
18+ PatchValue(dest, value interface{})
19+}
20+
21+func PatchFacades(patcher Patcher) {
22+ emptyFacades := registry.NewTypedNameVersion(facadeFactoryType)
23+ patcher.PatchValue(&Facades, emptyFacades)
24+}
25
26=== modified file 'state/apiserver/common/registry.go'
27--- state/apiserver/common/registry.go 2014-05-26 10:02:18 +0000
28+++ state/apiserver/common/registry.go 2014-05-26 10:02:19 +0000
29@@ -23,9 +23,18 @@
30 interface{}, error,
31 )
32
33+type facadeRecord struct {
34+ factory FacadeFactory
35+ facadeType reflect.Type
36+}
37+
38 // RegisterFacade updates the global facade registry with a new version of a new type.
39-func RegisterFacade(name string, version int, factory FacadeFactory) {
40- err := Facades.Register(name, version, factory)
41+func RegisterFacade(name string, version int, factory FacadeFactory, facadeType reflect.Type) {
42+ record := facadeRecord{
43+ factory: factory,
44+ facadeType: facadeType,
45+ }
46+ err := Facades.Register(name, version, record)
47 if err != nil {
48 // This is meant to be called during init() so errors should be
49 // considered fatal.
50@@ -68,11 +77,11 @@
51
52 // wrapNewFacade turns a given NewFoo(st, resources, authorizer) (*Instance, error)
53 // function and wraps it into a proper FacadeFactory function.
54-func wrapNewFacade(newFunc interface{}) (FacadeFactory, error) {
55+func wrapNewFacade(newFunc interface{}) (FacadeFactory, reflect.Type, error) {
56 funcValue := reflect.ValueOf(newFunc)
57 err := validateNewFacade(funcValue)
58 if err != nil {
59- return nil, err
60+ return nil, reflect.TypeOf(nil), err
61 }
62 // So we know newFunc is a func with the right args in and out, so
63 // wrap it into a helper function that matches the FacadeFactory.
64@@ -100,7 +109,7 @@
65 }
66 return out[0].Interface(), nil
67 }
68- return wrapped, nil
69+ return wrapped, funcValue.Type().Out(0), nil
70 }
71
72 // RegisterStandardFacade registers a factory function for a normal New* style
73@@ -109,14 +118,16 @@
74 // With that syntax, we will create a helper function that wraps calling NewFoo
75 // with the right parameters, and returns the *Type correctly.
76 func RegisterStandardFacade(name string, version int, newFunc interface{}) {
77- wrapped, err := wrapNewFacade(newFunc)
78+ wrapped, facadeType, err := wrapNewFacade(newFunc)
79 if err != nil {
80 panic(err)
81 }
82- RegisterFacade(name, version, wrapped)
83+ RegisterFacade(name, version, wrapped, facadeType)
84 }
85
86-func GetFacade(name string, version int) (FacadeFactory, error) {
87+// GetFacadeFactory returns the factory that can be used to create an instance
88+// of the Facade.
89+func GetFacadeFactory(name string, version int) (FacadeFactory, error) {
90 f, err := Facades.Get(name, version)
91 if err != nil {
92 if errors.IsNotFound(err) {
93@@ -129,9 +140,19 @@
94 }
95 // We don't need to check the type because registry.TypedNameVersion
96 // should ensure we have a proper FacadeFactory.
97- return f.(FacadeFactory), nil
98-}
99-
100-var facadeFactoryType = reflect.TypeOf((*FacadeFactory)(nil)).Elem()
101+ return f.(facadeRecord).factory, nil
102+}
103+
104+// GetFacadeType can return the concrete type that will be returned from the
105+// FacadeFactory.
106+func GetFacadeType(name string, version int) (reflect.Type, error) {
107+ f, err := Facades.Get(name, version)
108+ if err != nil {
109+ return reflect.TypeOf(nil), err
110+ }
111+ return f.(facadeRecord).facadeType, nil
112+}
113+
114+var facadeFactoryType = reflect.TypeOf((*facadeRecord)(nil)).Elem()
115
116 var Facades = registry.NewTypedNameVersion(facadeFactoryType)
117
118=== modified file 'state/apiserver/common/registry_test.go'
119--- state/apiserver/common/registry_test.go 2014-05-26 10:02:18 +0000
120+++ state/apiserver/common/registry_test.go 2014-05-26 10:02:19 +0000
121@@ -13,7 +13,6 @@
122 "launchpad.net/juju-core/state/apiserver/common"
123 apiservertesting "launchpad.net/juju-core/state/apiserver/testing"
124 "launchpad.net/juju-core/testing/testbase"
125- "launchpad.net/juju-core/utils/registry"
126 )
127
128 type facadeRegistrySuite struct {
129@@ -34,15 +33,14 @@
130 // registered Facades.
131
132 // a raw type isn't an expression, so we have to play tricks.
133- factoryType := reflect.TypeOf((*common.FacadeFactory)(nil)).Elem()
134- emptyFacades := registry.NewTypedNameVersion(factoryType)
135- s.PatchValue(&common.Facades, emptyFacades)
136+ common.PatchFacades(s)
137 }
138
139 func (s *facadeRegistrySuite) TestRegister(c *gc.C) {
140 s.sanitizeFacades()
141- common.RegisterFacade("myfacade", 0, testFacade)
142- f, err := common.GetFacade("myfacade", 0)
143+ var v interface{}
144+ common.RegisterFacade("myfacade", 0, testFacade, reflect.TypeOf(&v).Elem())
145+ f, err := common.GetFacadeFactory("myfacade", 0)
146 c.Assert(err, gc.IsNil)
147 val, err := f(nil, nil, nil, "")
148 c.Assert(err, gc.IsNil)
149@@ -51,8 +49,9 @@
150
151 func (s *facadeRegistrySuite) TestGetFacadeBadName(c *gc.C) {
152 s.sanitizeFacades()
153- common.RegisterFacade("myfacade", 0, testFacade)
154- _, err := common.GetFacade("notmyfacade", 0)
155+ var v interface{}
156+ common.RegisterFacade("myfacade", 0, testFacade, reflect.TypeOf(&v).Elem())
157+ _, err := common.GetFacadeFactory("notmyfacade", 0)
158 c.Assert(err, gc.NotNil)
159 c.Assert(err, gc.FitsTypeOf, (*rpcreflect.CallNotImplementedError)(nil))
160 c.Assert(err, gc.ErrorMatches, `unknown object type "notmyfacade"`)
161@@ -60,8 +59,9 @@
162
163 func (s *facadeRegistrySuite) TestGetFacadeBadVersion(c *gc.C) {
164 s.sanitizeFacades()
165- common.RegisterFacade("myfacade", 0, testFacade)
166- _, err := common.GetFacade("myfacade", 1)
167+ var v interface{}
168+ common.RegisterFacade("myfacade", 0, testFacade, reflect.TypeOf(v))
169+ _, err := common.GetFacadeFactory("myfacade", 1)
170 c.Assert(err, gc.NotNil)
171 c.Assert(err, gc.FitsTypeOf, (*rpcreflect.CallNotImplementedError)(nil))
172 c.Assert(err, gc.ErrorMatches, `unknown version \(1\) of interface "myfacade"`)
173@@ -71,9 +71,12 @@
174 // proper CodeNotImplemented.
175
176 func (s *facadeRegistrySuite) TestRegisterFacadePanicsOnDoubleRegistry(c *gc.C) {
177- common.RegisterFacade("myfacade", 0, testFacade)
178- c.Assert(func() { common.RegisterFacade("myfacade", 0, testFacade) },
179- gc.PanicMatches, `object "myfacade\(0\)" already registered`)
180+ var v interface{}
181+ doRegister := func() {
182+ common.RegisterFacade("myfacade", 0, testFacade, reflect.TypeOf(v))
183+ }
184+ doRegister()
185+ c.Assert(doRegister, gc.PanicMatches, `object "myfacade\(0\)" already registered`)
186 }
187
188 func checkValidateNewFacadeFailsWith(c *gc.C, obj interface{}, errMsg string) {
189@@ -126,12 +129,12 @@
190 }
191
192 func (*facadeRegistrySuite) TestWrapNewFacadeFailure(c *gc.C) {
193- _, err := common.WrapNewFacade("notafunc")
194+ _, _, err := common.WrapNewFacade("notafunc")
195 c.Check(err, gc.ErrorMatches, `wrong type "string" is not a function`)
196 }
197
198 func (*facadeRegistrySuite) TestWrapNewFacadeHandlesId(c *gc.C) {
199- wrapped, err := common.WrapNewFacade(validFactory)
200+ wrapped, _, err := common.WrapNewFacade(validFactory)
201 c.Assert(err, gc.IsNil)
202 val, err := wrapped(nil, nil, nil, "badId")
203 c.Check(err, gc.ErrorMatches, "id not found")
204@@ -139,7 +142,7 @@
205 }
206
207 func (*facadeRegistrySuite) TestWrapNewFacadeCallsFunc(c *gc.C) {
208- wrapped, err := common.WrapNewFacade(validFactory)
209+ wrapped, _, err := common.WrapNewFacade(validFactory)
210 c.Assert(err, gc.IsNil)
211 val, err := wrapped(nil, nil, nil, "")
212 c.Assert(err, gc.IsNil)
213@@ -161,7 +164,9 @@
214 ) (*myResult, error) {
215 return &myResult{st, resources, authorizer}, nil
216 }
217- wrapped, err := common.WrapNewFacade(testFunc)
218+ wrapped, facadeType, err := common.WrapNewFacade(testFunc)
219+ c.Assert(err, gc.IsNil)
220+ c.Check(facadeType, gc.Equals, reflect.TypeOf((*myResult)(nil)))
221 val, err := wrapped(nil, resources, authorizer, "")
222 c.Assert(err, gc.IsNil)
223 asResult := val.(*myResult)
224@@ -173,7 +178,7 @@
225 func (r *facadeRegistrySuite) TestRegisterStandardFacade(c *gc.C) {
226 r.sanitizeFacades()
227 common.RegisterStandardFacade("testing", 0, validFactory)
228- wrapped, err := common.GetFacade("testing", 0)
229+ wrapped, err := common.GetFacadeFactory("testing", 0)
230 c.Assert(err, gc.IsNil)
231 val, err := wrapped(nil, nil, nil, "")
232 c.Assert(err, gc.IsNil)
233@@ -186,42 +191,24 @@
234 func() { common.RegisterStandardFacade("badtest", 0, noArgs) },
235 gc.PanicMatches,
236 `function ".*noArgs" does not take 3 parameters and return 2`)
237- _, err := common.GetFacade("badtest", 0)
238+ _, err := common.GetFacadeFactory("badtest", 0)
239 c.Assert(err, gc.FitsTypeOf, (*rpcreflect.CallNotImplementedError)(nil))
240 c.Assert(err, gc.ErrorMatches, `unknown object type "badtest"`)
241 }
242 func (*facadeRegistrySuite) TestDiscardedAPIMethods(c *gc.C) {
243 allFacades := common.Facades.List()
244 c.Assert(allFacades, gc.Not(gc.HasLen), 0)
245- // We use a FakeAuthorizer that says it is allowed to do everything, so
246- // that we can get all of the concrete Facades
247- authorizer := apiservertesting.FakeAuthorizer{
248- Tag: "user-admin",
249- LoggedIn: true,
250- Client: true,
251- EnvironManager: true,
252- MachineAgent: true,
253- UnitAgent: true,
254- // Entity ?
255- }
256- resources := common.NewResources()
257- defer resources.StopAll()
258-
259 for _, description := range allFacades {
260 for _, version := range description.Versions {
261- factory, err := common.GetFacade(description.Name, version)
262- c.Assert(err, gc.IsNil)
263- obj, err := factory(nil, resources, authorizer, "")
264- c.Assert(err, gc.IsNil)
265- value := reflect.ValueOf(obj)
266- facadeType := rpcreflect.ObjTypeOf(value.Type())
267+ facadeType, err := common.GetFacadeType(description.Name, version)
268+ c.Assert(err, gc.IsNil)
269+ facadeObjType := rpcreflect.ObjTypeOf(facadeType)
270 // We must have some methods on every object returned
271 // by a root-level method.
272- c.Assert(facadeType.MethodNames(), gc.Not(gc.HasLen), 0)
273+ c.Assert(facadeObjType.MethodNames(), gc.Not(gc.HasLen), 0)
274 // We don't allow any methods that don't implement
275 // an RPC entry point.
276- c.Assert(facadeType.DiscardedMethods(), gc.HasLen, 0)
277- resources.StopAll()
278+ c.Assert(facadeObjType.DiscardedMethods(), gc.HasLen, 0)
279 }
280 }
281 }
282
283=== modified file 'state/apiserver/root.go'
284--- state/apiserver/root.go 2014-05-26 10:02:18 +0000
285+++ state/apiserver/root.go 2014-05-26 10:02:19 +0000
286@@ -68,7 +68,7 @@
287 // that has a Call() method that will invoke the concrete method on a live
288 // object.
289 func (r *srvRoot) MethodCaller(rootMethodName string, version int, objId, objMethodName string) (rpcreflect.MethodCaller, error) {
290- factory, err := common.GetFacade(rootMethodName, version)
291+ factory, err := common.GetFacadeFactory(rootMethodName, version)
292 if err != nil {
293 return rpcreflect.MethodCaller{}, err
294 }
295
296=== modified file 'state/apiserver/usermanager/usermanager.go'
297--- state/apiserver/usermanager/usermanager.go 2014-05-26 10:02:18 +0000
298+++ state/apiserver/usermanager/usermanager.go 2014-05-26 10:02:19 +0000
299@@ -16,15 +16,7 @@
300 var logger = loggo.GetLogger("juju.state.apiserver.usermanager")
301
302 func init() {
303- common.RegisterFacade("UserManager", 0,
304- func(
305- st *state.State, resources *common.Resources,
306- authorizer common.Authorizer, id string,
307- ) (
308- interface{}, error,
309- ) {
310- return NewUserManagerAPI(st, authorizer)
311- })
312+ common.RegisterStandardFacade("UserManager", 0, NewUserManagerAPI)
313 }
314
315 // UserManager defines the methods on the usermanager API end point.
316@@ -45,6 +37,7 @@
317
318 func NewUserManagerAPI(
319 st *state.State,
320+ resources *common.Resources,
321 authorizer common.Authorizer,
322 ) (*UserManagerAPI, error) {
323 if !authorizer.AuthClient() {
324
325=== modified file 'state/apiserver/usermanager/usermanager_test.go'
326--- state/apiserver/usermanager/usermanager_test.go 2014-04-17 12:47:50 +0000
327+++ state/apiserver/usermanager/usermanager_test.go 2014-05-26 10:02:19 +0000
328@@ -31,14 +31,14 @@
329 }
330
331 var err error
332- s.usermanager, err = usermanager.NewUserManagerAPI(s.State, s.authorizer)
333+ s.usermanager, err = usermanager.NewUserManagerAPI(s.State, nil, s.authorizer)
334 c.Assert(err, gc.IsNil)
335 }
336
337 func (s *userManagerSuite) TestNewUserManagerAPIRefusesNonClient(c *gc.C) {
338 anAuthoriser := s.authorizer
339 anAuthoriser.Client = false
340- endPoint, err := usermanager.NewUserManagerAPI(s.State, anAuthoriser)
341+ endPoint, err := usermanager.NewUserManagerAPI(s.State, nil, anAuthoriser)
342 c.Assert(endPoint, gc.IsNil)
343 c.Assert(err, gc.ErrorMatches, "permission denied")
344 }
345
346=== modified file 'state/apiserver/watcher.go'
347--- state/apiserver/watcher.go 2014-05-26 10:02:18 +0000
348+++ state/apiserver/watcher.go 2014-05-26 10:02:19 +0000
349@@ -4,6 +4,8 @@
350 package apiserver
351
352 import (
353+ "reflect"
354+
355 "launchpad.net/juju-core/state"
356 "launchpad.net/juju-core/state/api/params"
357 "launchpad.net/juju-core/state/apiserver/common"
358@@ -11,10 +13,22 @@
359 )
360
361 func init() {
362- common.RegisterFacade("AllWatcher", 0, newClientAllWatcher)
363- common.RegisterFacade("NotifyWatcher", 0, newNotifyWatcher)
364- common.RegisterFacade("StringsWatcher", 0, newStringsWatcher)
365- common.RegisterFacade("RelationUnitsWatcher", 0, newRelationUnitsWatcher)
366+ common.RegisterFacade(
367+ "AllWatcher", 0, newClientAllWatcher,
368+ reflect.TypeOf((*srvClientAllWatcher)(nil)),
369+ )
370+ common.RegisterFacade(
371+ "NotifyWatcher", 0, newNotifyWatcher,
372+ reflect.TypeOf((*srvNotifyWatcher)(nil)),
373+ )
374+ common.RegisterFacade(
375+ "StringsWatcher", 0, newStringsWatcher,
376+ reflect.TypeOf((*srvStringsWatcher)(nil)),
377+ )
378+ common.RegisterFacade(
379+ "RelationUnitsWatcher", 0, newRelationUnitsWatcher,
380+ reflect.TypeOf((*srvRelationUnitsWatcher)(nil)),
381+ )
382 }
383
384 // srvClientAllWatcher defines the API methods on a state/multiwatcher.Watcher,

Subscribers

People subscribed via source and target branches

to status/vote changes: