juju/juju — pull request #219 by jameinel (2014-07-02 06:58:09+00:00)
Title: Update client side of Facades for API Versioning

This PR combines https://github.com/juju/juju/pull/218 and the incremental diff https://github.com/jameinel/juju/pull/4. It is recommended that you review those changes in the incremental form for better clarity of what is going on. As I am intending to land them only as their combined form, I'm including the overview comments for both here.

This updates the client-side of the code to handle API versioning. (By client, this means User facing and Agent facing.)

This is the first in a series of 2 patches. This first one lays the groundwork and has the 'interesting' changes, the next patch has the giant mechanical change as we rewrite all of the api.Client* objects to use helpers rather than re-implementing everything in each one.

Overview of changes:

1) api.State.Call renamed to api.State.APICall. We had a lot of objects that implement some sort of Call interface. Try doing "grep -rnI .Call" and you'll see how many places are using it, and not all of those actually match very well. I felt this makes it a lot clearer when a given line of code is actually making an RPC request, vs just doing a local call.

2) Instead of having most of the client facades have their own "def call" implementation that wraps the 5-parameter Call into a 3-parameter call, implement that same thing as base.FacadeCaller and have all of these implementations use that. Part of the motivation here is that we need to update all of that code to start passing version information, and it is far easier to just do it right in a common helper.

3) Implement base.FacadeCaller (note that the function name here is FacadeCall, again to distinguish what layer we are at. The old code was call() calling apistate.Call() calling rpcreflect.Call() which would go over the api, and call reflect.Call of an actual method, etc.)

4) Implement BestFacadeVersion. The logic is that on the client-side (juju) we store all of the best versions that we know about, and use that information to select the newest version from the server that is <= the one that we want. You can see the code in 'facadeversions.go'.

This also adds a test that the versions stored in facadeversions.go match the actual best version that is available in the apiserver code. They are intentionally stored separately, because we don't want our runtime 'juju' code to actually depend on apiserver code. (Logically, apiserver should actually not be compiled into the 'juju' client, whether we actually manage that in real life is a different matter.)

5) Update some of the 'common' code for the FacadeCaller paradigm. There are a lot of changes that follow this as this spreads to all the other api facades, but I wanted to only have a little bit of that code to directly review.
In general, it means stuff like "common.Life" that used to take a Caller and a facadeName, can just take the FacadeCaller directly.

6) There is one more base.ClientFacade change. This is for "User" facades that want to expose BestAPIVersion and Close to higher level client code (like cmd/juju level code). In that case, each User facing facade can just embed the ClientFacade interface (as well as using a FacadeCaller). You'll see the specific changes for that in the next patch (api.Client, KeyManager and UserManager are all user facing).

This lets us do stuff like proper handling for code like 'juju backup' that should check the API Version before deciding whether Backup is available, and giving a better error message to the user (Backup not available in this version of juju.)

7) Lots of mechanical changes to rework all of the state/api/* code to use the new base.FacadeCaller and base.ClientFacade implementations. This also makes all of that code version-aware, even though it isn't making much use of it yet.