import websockets
from concurrent.futures import CancelledError
from http.client import HTTPSConnection
+from pathlib import Path
import asyncio
import yaml
from juju import tag, utils
from juju.client import client
-from juju.client.version_map import VERSION_MAP
from juju.errors import JujuError, JujuAPIError, JujuConnectionError
from juju.utils import IdQueue
"""
jujudata = JujuData()
+
controller_name = jujudata.current_controller()
+ if not controller_name:
+ raise JujuConnectionError('No current controller')
+
model_name = jujudata.current_model()
return await cls.connect_model(
accounts = jujudata.accounts()[controller_name]
username = accounts['user']
password = accounts.get('password')
- macaroons = get_macaroons() if not password else None
+ macaroons = get_macaroons(controller_name) if not password else None
return await cls.connect(
endpoint, None, username, password, cacert, macaroons, loop)
password = accounts.get('password')
models = jujudata.models()[controller_name]
model_uuid = models['models'][model_name]['uuid']
- macaroons = get_macaroons() if not password else None
+ macaroons = get_macaroons(controller_name) if not password else None
return await cls.connect(
endpoint, model_uuid, username, password, cacert, macaroons, loop)
def build_facades(self, facades):
self.facades.clear()
- # In order to work around an issue where the juju api is not
- # returning a complete list of facades, we simply look up the
- # juju version in a pregenerated map, and use that info to
- # populate our list of facades.
-
- # TODO: if a future version of juju fixes this bug, restore
- # the following code for that version and higher:
- # for facade in facades:
- # self.facades[facade['name']] = facade['versions'][-1]
- try:
- self.facades = VERSION_MAP[self.info['server-version']]
- except KeyError:
- log.warning("Could not find a set of facades for {}. Using "
- "the latest facade set instead".format(
- self.info['server-version']))
- self.facades = VERSION_MAP['latest']
+ for facade in facades:
+ self.facades[facade['name']] = facade['versions'][-1]
async def login(self):
username = self.username
return yaml.safe_load(f)[key]
-def get_macaroons():
+def get_macaroons(controller_name=None):
"""Decode and return macaroons from default ~/.go-cookies
"""
- try:
- cookie_file = os.path.expanduser('~/.go-cookies')
- with open(cookie_file, 'r') as f:
- cookies = json.load(f)
- except (OSError, ValueError):
- log.warn("Couldn't load macaroons from %s", cookie_file)
+ cookie_files = []
+ if controller_name:
+ cookie_files.append('~/.local/share/juju/cookies/{}.json'.format(
+ controller_name))
+ cookie_files.append('~/.go-cookies')
+ for cookie_file in cookie_files:
+ cookie_file = Path(cookie_file).expanduser()
+ if cookie_file.exists():
+ try:
+ cookies = json.loads(cookie_file.read_text())
+ break
+ except (OSError, ValueError):
+ log.warn("Couldn't load macaroons from %s", cookie_file)
+ return []
+ else:
+ log.warn("Couldn't load macaroons from %s", ' or '.join(cookie_files))
return []
base64_macaroons = [