X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=juju%2Fclient%2Fconnection.py;h=b508a1ac924ebf692eaef432ef3be471b86b2d37;hb=27dfe759bbb54ca7dc963c30f6c52406c456983a;hp=f4081355c686b56ac3e5842c5e35e4101d4699cd;hpb=63413d09a6fae28fd1fec1ea07bb10b368d561c9;p=osm%2FN2VC.git diff --git a/juju/client/connection.py b/juju/client/connection.py index f408135..b508a1a 100644 --- a/juju/client/connection.py +++ b/juju/client/connection.py @@ -11,10 +11,11 @@ import subprocess import websockets from http.client import HTTPSConnection +import asyncio import yaml from juju import tag -from juju.errors import JujuAPIError, JujuConnectionError, JujuError +from juju.errors import JujuError, JujuAPIError, JujuConnectionError log = logging.getLogger("websocket") @@ -33,16 +34,19 @@ class Connection: # Connect to the currently active model client = await Connection.connect_current() + Note: Any connection method or constructor can accept an optional `loop` + argument to override the default event loop from `asyncio.get_event_loop`. """ def __init__( self, endpoint, uuid, username, password, cacert=None, - macaroons=None): + macaroons=None, loop=None): self.endpoint = endpoint self.uuid = uuid self.username = username self.password = password self.macaroons = macaroons self.cacert = cacert + self.loop = loop or asyncio.get_event_loop() self.__request_id__ = 0 self.addr = None @@ -67,6 +71,7 @@ class Connection: kw = dict() kw['ssl'] = self._get_ssl(self.cacert) + kw['loop'] = self.loop self.addr = url self.ws = await websockets.connect(url, **kw) log.info("Driver connected to juju %s", url) @@ -175,6 +180,7 @@ class Connection: self.password, self.cacert, self.macaroons, + self.loop, ) async def controller(self): @@ -188,19 +194,21 @@ class Connection: self.password, self.cacert, self.macaroons, + self.loop, ) @classmethod async def connect( cls, endpoint, uuid, username, password, cacert=None, - macaroons=None): + macaroons=None, loop=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) + client = cls(endpoint, uuid, username, password, cacert, macaroons, + loop) await client.open() redirect_info = await client.redirect_info() @@ -231,20 +239,19 @@ class Connection: "Couldn't authenticate to %s", endpoint) @classmethod - async def connect_current(cls): + async def connect_current(cls, loop=None): """Connect to the currently active model. """ jujudata = JujuData() controller_name = jujudata.current_controller() - models = jujudata.models()[controller_name] - model_name = models['current-model'] + model_name = jujudata.current_model() return await cls.connect_model( - '{}:{}'.format(controller_name, model_name)) + '{}:{}'.format(controller_name, model_name), loop) @classmethod - async def connect_current_controller(cls): + async def connect_current_controller(cls, loop=None): """Connect to the currently active controller. """ @@ -253,10 +260,10 @@ class Connection: if not controller_name: raise JujuConnectionError('No current controller') - return await cls.connect_controller(controller_name) + return await cls.connect_controller(controller_name, loop) @classmethod - async def connect_controller(cls, controller_name): + async def connect_controller(cls, controller_name, loop=None): """Connect to a controller by name. """ @@ -270,30 +277,41 @@ class Connection: macaroons = get_macaroons() if not password else None return await cls.connect( - endpoint, None, username, password, cacert, macaroons) + endpoint, None, username, password, cacert, macaroons, loop) @classmethod - async def connect_model(cls, model): + async def connect_model(cls, model, loop=None): """Connect to a model by name. - :param str model: : + :param str model: [:] """ - controller_name, model_name = model.split(':') - jujudata = JujuData() + + if ':' in model: + # explicit controller given + controller_name, model_name = model.split(':') + else: + # use the current controller if one isn't explicitly given + controller_name = jujudata.current_controller() + model_name = model + + accounts = jujudata.accounts()[controller_name] + username = accounts['user'] + # model name must include a user prefix, so add it if it doesn't + if '/' not in model_name: + model_name = '{}/{}'.format(username, model_name) + 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) + endpoint, model_uuid, username, password, cacert, macaroons, loop) def build_facades(self, info): self.facades.clear() @@ -348,6 +366,14 @@ class JujuData: output = yaml.safe_load(output) return output.get('current-controller', '') + def current_model(self, controller_name=None): + if not controller_name: + controller_name = self.current_controller() + models = self.models()[controller_name] + if 'current-model' not in models: + raise JujuError('No current model') + return models['current-model'] + def controllers(self): return self._load_yaml('controllers.yaml', 'controllers') @@ -371,7 +397,7 @@ def get_macaroons(): cookie_file = os.path.expanduser('~/.go-cookies') with open(cookie_file, 'r') as f: cookies = json.load(f) - except (OSError, ValueError) as e: + except (OSError, ValueError): log.warn("Couldn't load macaroons from %s", cookie_file) return []