Update libjuju

- fix licensing quirks
- refresh against libjuju master

Signed-off-by: Adam Israel <adam.israel@canonical.com>
diff --git a/modules/libjuju/juju/client/_client.py b/modules/libjuju/juju/client/_client.py
index d510e11..2ef0ffd 100644
--- a/modules/libjuju/juju/client/_client.py
+++ b/modules/libjuju/juju/client/_client.py
@@ -1,7 +1,7 @@
 # DO NOT CHANGE THIS FILE! This file is auto-generated by facade.py.
 # Changes will be overwritten/lost when the file is regenerated.
 
-from juju.client._definitions import *
+from juju.client._definitions import *  # noqa
 
 from juju.client import _client1, _client2, _client3, _client4, _client5
 
@@ -15,22 +15,21 @@
 }
 
 
-
 def lookup_facade(name, version):
         """
         Given a facade name and version, attempt to pull that facade out
         of the correct client<version>.py file.
 
         """
-        try:
-            facade = getattr(CLIENTS[str(version)], name)
-        except KeyError:
-            raise ImportError("No facades found for version {}".format(version))
-        except AttributeError:
-            raise ImportError(
-                "No facade with name '{}' in version {}".format(name, version))
-        return facade
-
+        for _version in range(int(version), 0, -1):
+            try:
+                facade = getattr(CLIENTS[str(_version)], name)
+                return facade
+            except (KeyError, AttributeError):
+                continue
+        else:
+            raise ImportError("No supported version for facade: "
+                              "{}".format(name))
 
 
 class TypeFactory:
@@ -363,5 +362,3 @@
 
 class VolumeAttachmentsWatcherFacade(TypeFactory):
     pass
-
-
diff --git a/modules/libjuju/juju/client/client.py b/modules/libjuju/juju/client/client.py
index 89b5248..2f3e49d 100644
--- a/modules/libjuju/juju/client/client.py
+++ b/modules/libjuju/juju/client/client.py
@@ -5,7 +5,7 @@
 
 
 for o in overrides.__all__:
-    if not "Facade" in o:
+    if "Facade" not in o:
         # Override stuff in _definitions, which is all imported
         # into _client. We Monkey patch both the original class and
         # the ref in _client (import shenanigans are fun!)
diff --git a/modules/libjuju/juju/client/connection.py b/modules/libjuju/juju/client/connection.py
index 7457391..c09468c 100644
--- a/modules/libjuju/juju/client/connection.py
+++ b/modules/libjuju/juju/client/connection.py
@@ -413,7 +413,7 @@
             endpoints.extend(new_endpoints)
         else:
             # ran out of endpoints without a successful login
-            raise Exception("Couldn't authenticate to {}".format(
+            raise JujuConnectionError("Couldn't authenticate to {}".format(
                 self._endpoint))
 
         response = result['response']
@@ -584,6 +584,38 @@
     def accounts(self):
         return self._load_yaml('accounts.yaml', 'controllers')
 
+    def credentials(self):
+        return self._load_yaml('credentials.yaml', 'credentials')
+
+    def load_credential(self, cloud, name=None):
+        """Load a local credential.
+
+        :param str cloud: Name of cloud to load credentials from.
+        :param str name: Name of credential. If None, the default credential
+            will be used, if available.
+        :returns: A CloudCredential instance, or None.
+        """
+        try:
+            cloud = tag.untag('cloud-', cloud)
+            creds_data = self.credentials()[cloud]
+            if not name:
+                default_credential = creds_data.pop('default-credential', None)
+                default_region = creds_data.pop('default-region', None)  # noqa
+                if default_credential:
+                    name = creds_data['default-credential']
+                elif len(creds_data) == 1:
+                    name = list(creds_data)[0]
+                else:
+                    return None, None
+            cred_data = creds_data[name]
+            auth_type = cred_data.pop('auth-type')
+            return name, client.CloudCredential(
+                auth_type=auth_type,
+                attrs=cred_data,
+            )
+        except (KeyError, FileNotFoundError):
+            return None, None
+
     def _load_yaml(self, filename, key):
         filepath = os.path.join(self.path, filename)
         with io.open(filepath, 'rt') as f:
diff --git a/modules/libjuju/juju/client/facade.py b/modules/libjuju/juju/client/facade.py
index c959e01..c015c5f 100644
--- a/modules/libjuju/juju/client/facade.py
+++ b/modules/libjuju/juju/client/facade.py
@@ -44,19 +44,19 @@
 # Classes and helper functions that we'll write to _client.py
 LOOKUP_FACADE = '''
 def lookup_facade(name, version):
-        """
-        Given a facade name and version, attempt to pull that facade out
-        of the correct client<version>.py file.
+    """
+    Given a facade name and version, attempt to pull that facade out
+    of the correct client<version>.py file.
 
-        """
-        try:
-            facade = getattr(CLIENTS[str(version)], name)
-        except KeyError:
-            raise ImportError("No facades found for version {}".format(version))
-        except AttributeError:
-            raise ImportError(
-                "No facade with name '{}' in version {}".format(name, version))
-        return facade
+    """
+    try:
+        facade = getattr(CLIENTS[str(version)], name)
+    except KeyError:
+        raise ImportError("No facades found for version {}".format(version))
+    except AttributeError:
+        raise ImportError(
+            "No facade with name '{}' in version {}".format(name, version))
+    return facade
 
 
 '''
@@ -127,6 +127,7 @@
 
         return self[refname]
 
+
 _types = TypeRegistry()
 _registry = KindRegistry()
 CLASSES = {}
@@ -257,7 +258,7 @@
     for kind in sorted((k for k in _types if not isinstance(k, str)),
                        key=lambda x: str(x)):
         name = _types[kind]
-        if name in capture and not name in NAUGHTY_CLASSES:
+        if name in capture and name not in NAUGHTY_CLASSES:
             continue
         args = Args(kind)
         # Write Factory class for _client.py
@@ -277,9 +278,7 @@
             pprint.pformat(args.SchemaToPyMapping(), width=999),
             ", " if args else "",
             args.as_kwargs(),
-            textwrap.indent(args.get_doc(), INDENT * 2))
-                  ]
-        assignments = args._get_arg_str(False, False)
+            textwrap.indent(args.get_doc(), INDENT * 2))]
 
         if not args:
             source.append("{}pass".format(INDENT * 2))
@@ -289,7 +288,9 @@
                 arg_type = arg[1]
                 arg_type_name = strcast(arg_type)
                 if arg_type in basic_types:
-                    source.append("{}self.{} = {}".format(INDENT * 2, arg_name, arg_name))
+                    source.append("{}self.{} = {}".format(INDENT * 2,
+                                                          arg_name,
+                                                          arg_name))
                 elif issubclass(arg_type, typing.Sequence):
                     value_type = (
                         arg_type_name.__parameters__[0]
@@ -297,10 +298,16 @@
                         else None
                     )
                     if type(value_type) is typing.TypeVar:
-                        source.append("{}self.{} = [{}.from_json(o) for o in {} or []]".format(
-                            INDENT * 2, arg_name, strcast(value_type), arg_name))
+                        source.append(
+                            "{}self.{} = [{}.from_json(o) "
+                            "for o in {} or []]".format(INDENT * 2,
+                                                        arg_name,
+                                                        strcast(value_type),
+                                                        arg_name))
                     else:
-                        source.append("{}self.{} = {}".format(INDENT * 2, arg_name, arg_name))
+                        source.append("{}self.{} = {}".format(INDENT * 2,
+                                                              arg_name,
+                                                              arg_name))
                 elif issubclass(arg_type, typing.Mapping):
                     value_type = (
                         arg_type_name.__parameters__[1]
@@ -308,15 +315,28 @@
                         else None
                     )
                     if type(value_type) is typing.TypeVar:
-                        source.append("{}self.{} = {{k: {}.from_json(v) for k, v in ({} or dict()).items()}}".format(
-                            INDENT * 2, arg_name, strcast(value_type), arg_name))
+                        source.append(
+                            "{}self.{} = {{k: {}.from_json(v) "
+                            "for k, v in ({} or dict()).items()}}".format(
+                                INDENT * 2,
+                                arg_name,
+                                strcast(value_type),
+                                arg_name))
                     else:
-                        source.append("{}self.{} = {}".format(INDENT * 2, arg_name, arg_name))
+                        source.append("{}self.{} = {}".format(INDENT * 2,
+                                                              arg_name,
+                                                              arg_name))
                 elif type(arg_type) is typing.TypeVar:
-                    source.append("{}self.{} = {}.from_json({}) if {} else None".format(
-                        INDENT * 2, arg_name, arg_type_name, arg_name, arg_name))
+                    source.append("{}self.{} = {}.from_json({}) "
+                                  "if {} else None".format(INDENT * 2,
+                                                           arg_name,
+                                                           arg_type_name,
+                                                           arg_name,
+                                                           arg_name))
                 else:
-                    source.append("{}self.{} = {}".format(INDENT * 2, arg_name, arg_name))
+                    source.append("{}self.{} = {}".format(INDENT * 2,
+                                                          arg_name,
+                                                          arg_name))
 
         source = "\n".join(source)
         capture.clear(name)
@@ -435,7 +455,10 @@
     '''
     # map input types to rpc msg
     _params = dict()
-    msg = dict(type='{cls.name}', request='{name}', version={cls.version}, params=_params)
+    msg = dict(type='{cls.name}',
+               request='{name}',
+               version={cls.version},
+               params=_params)
 {assignments}
     reply = {await}self.rpc(msg)
     return reply
@@ -539,7 +562,7 @@
         return d
 
     def to_json(self):
-        return json.dumps(self.serialize())
+        return json.dumps(self.serialize(), cls=TypeEncoder, sort_keys=True)
 
 
 class Schema(dict):
@@ -576,7 +599,7 @@
         if not defs:
             return
         for d, data in defs.items():
-            if d in _registry and not d in NAUGHTY_CLASSES:
+            if d in _registry and d not in NAUGHTY_CLASSES:
                 continue
             node = self.deref(data, d)
             kind = node.get("type")
@@ -762,6 +785,7 @@
 
     return captures
 
+
 def setup():
     parser = argparse.ArgumentParser()
     parser.add_argument("-s", "--schema", default="juju/client/schemas*")
@@ -769,6 +793,7 @@
     options = parser.parse_args()
     return options
 
+
 def main():
     options = setup()
 
@@ -780,5 +805,6 @@
     write_definitions(captures, options, last_version)
     write_client(captures, options)
 
+
 if __name__ == '__main__':
     main()
diff --git a/modules/libjuju/juju/client/overrides.py b/modules/libjuju/juju/client/overrides.py
index f439adb..5e98e56 100644
--- a/modules/libjuju/juju/client/overrides.py
+++ b/modules/libjuju/juju/client/overrides.py
@@ -11,6 +11,7 @@
     'Number',
     'Binary',
     'ConfigValue',
+    'Resource',
 ]
 
 __patches__ = [
@@ -273,3 +274,47 @@
         return '<{} source={} value={}>'.format(type(self).__name__,
                                                 repr(self.source),
                                                 repr(self.value))
+
+
+class Resource(Type):
+    _toSchema = {'application': 'application',
+                 'charmresource': 'CharmResource',
+                 'id_': 'id',
+                 'pending_id': 'pending-id',
+                 'timestamp': 'timestamp',
+                 'username': 'username',
+                 'name': 'name',
+                 'origin': 'origin'}
+    _toPy = {'CharmResource': 'charmresource',
+             'application': 'application',
+             'id': 'id_',
+             'pending-id': 'pending_id',
+             'timestamp': 'timestamp',
+             'username': 'username',
+             'name': 'name',
+             'origin': 'origin'}
+
+    def __init__(self, charmresource=None, application=None, id_=None,
+                 pending_id=None, timestamp=None, username=None, name=None,
+                 origin=None, **unknown_fields):
+        '''
+        charmresource : CharmResource
+        application : str
+        id_ : str
+        pending_id : str
+        timestamp : str
+        username : str
+        name: str
+        origin : str
+        '''
+        if charmresource:
+            self.charmresource = _client.CharmResource.from_json(charmresource)
+        else:
+            self.charmresource = None
+        self.application = application
+        self.id_ = id_
+        self.pending_id = pending_id
+        self.timestamp = timestamp
+        self.username = username
+        self.name = name
+        self.origin = origin
diff --git a/modules/libjuju/juju/client/runner.py b/modules/libjuju/juju/client/runner.py
index 61f2963..6545bc4 100644
--- a/modules/libjuju/juju/client/runner.py
+++ b/modules/libjuju/juju/client/runner.py
@@ -1,6 +1,4 @@
 
-
-
 class AsyncRunner:
     async def __call__(self, facade_method, *args, **kwargs):
         await self.connection.rpc(facade_method(*args, **kwargs))
@@ -15,14 +13,9 @@
 # This could let us fake the protocol we want
 # while decoupling the protocol from the RPC and the IO/Process context
 
-# The problem is leaking the runtime impl details to the top levels of the API with
-# async def
-# By handling the Marshal/Unmarshal side of RPC as a protocol we can leave the RPC running to a specific
-# delegate without altering the method signatures.
-# This still isn't quite right though as async is co-op multitasking and the methods still need to know
-# not to block or they will pause other execution
-
-
-
-
-
+# The problem is leaking the runtime impl details to the top levels of the API
+# with async def By handling the Marshal/Unmarshal side of RPC as a protocol we
+# can leave the RPC running to a specific delegate without altering the method
+# signatures.  This still isn't quite right though as async is co-op
+# multitasking and the methods still need to know not to block or they will
+# pause other execution