+ async def connect(
+ cls, endpoint, uuid, username, password, cacert=None,
+ macaroons=None):
+ """Connect to the websocket.
+
+ If uuid is None, the connection will be to the controller. Otherwise it
+ will be to the model.
+
+ """
+ client = cls(endpoint, uuid, username, password, cacert, macaroons)
+ await client.open()
+
+ redirect_info = await client.redirect_info()
+ if not redirect_info:
+ await client.login(username, password, macaroons)
+ return client
+
+ await client.close()
+ servers = [
+ s for servers in redirect_info['servers']
+ for s in servers if s["scope"] == 'public'
+ ]
+ for server in servers:
+ client = cls(
+ "{value}:{port}".format(**server), uuid, username,
+ password, redirect_info['ca-cert'], macaroons)
+ await client.open()
+ try:
+ result = await client.login(username, password, macaroons)
+ if 'discharge-required-error' in result:
+ continue
+ return client
+ except Exception as e:
+ await client.close()
+ log.exception(e)
+
+ raise Exception(
+ "Couldn't authenticate to %s", endpoint)
+
+ @classmethod
+ async def connect_current(cls):
+ """Connect to the currently active model.
+
+ """
+ jujudata = JujuData()
+ controller_name = jujudata.current_controller()
+ models = jujudata.models()[controller_name]
+ model_name = models['current-model']
+
+ return await cls.connect_model(
+ '{}:{}'.format(controller_name, model_name))
+
+ @classmethod
+ async def connect_current_controller(cls):
+ """Connect to the currently active controller.
+
+ """
+ jujudata = JujuData()
+ controller_name = jujudata.current_controller()
+
+ return await cls.connect_controller(controller_name)
+
+ @classmethod
+ async def connect_controller(cls, controller_name):
+ """Connect to a controller by name.
+
+ """
+ jujudata = JujuData()
+ controller = jujudata.controllers()[controller_name]
+ endpoint = controller['api-endpoints'][0]
+ cacert = controller.get('ca-cert')
+ accounts = jujudata.accounts()[controller_name]
+ username = accounts['user']
+ password = accounts.get('password')
+ macaroons = get_macaroons() if not password else None
+
+ return await cls.connect(
+ endpoint, None, username, password, cacert, macaroons)
+
+ @classmethod
+ async def connect_model(cls, model):
+ """Connect to a model by name.
+
+ :param str model: <controller>:<model>
+
+ """
+ controller_name, model_name = model.split(':')
+
+ jujudata = JujuData()
+ controller = jujudata.controllers()[controller_name]
+ endpoint = controller['api-endpoints'][0]
+ cacert = controller.get('ca-cert')
+ accounts = jujudata.accounts()[controller_name]
+ username = accounts['user']
+ password = accounts.get('password')
+ models = jujudata.models()[controller_name]
+ model_uuid = models['models'][model_name]['uuid']
+ macaroons = get_macaroons() if not password else None
+
+ return await cls.connect(
+ endpoint, model_uuid, username, password, cacert, macaroons)