diff --git a/juju/client/connector.py b/juju/client/connector.py index e51f610cc..a5998c6a3 100644 --- a/juju/client/connector.py +++ b/juju/client/connector.py @@ -80,6 +80,18 @@ async def connect(self, **kwargs): else: if self._connection: await self._connection.close() + + account = kwargs.pop('account', {}) + # Prioritize the username and password that user provided + # If not enough, try to patch it with info from accounts.yaml + if 'username' not in kwargs and account.get('user'): + kwargs.update(username=account.get('user')) + if 'password' not in kwargs and account.get('password'): + kwargs.update(password=account.get('password')) + + if not ({'username', 'password'}.issubset(kwargs)): + required = {'username', 'password'}.difference(kwargs) + raise ValueError(f'Some authentication parameters are required : {",".join(required)}') self._connection = await Connection.connect(**kwargs) if not self.controller_name: @@ -103,7 +115,7 @@ async def disconnect(self): await self._log_connection.close() self._log_connection = None - async def connect_controller(self, controller_name=None, specified_facades=None): + async def connect_controller(self, controller_name=None, specified_facades=None, **kwargs): """Connect to a controller by name. If the name is empty, it connect to the current controller. """ @@ -118,16 +130,15 @@ async def connect_controller(self, controller_name=None, specified_facades=None) proxy = proxy_from_config(controller.get('proxy-config', None)) - await self.connect( - endpoint=endpoints, - uuid=None, - username=accounts.get('user'), - password=accounts.get('password'), - cacert=controller.get('ca-cert'), - bakery_client=self.bakery_client_for_controller(controller_name), - specified_facades=specified_facades, - proxy=proxy, - ) + kwargs.update(endpoint=endpoints, + uuid=None, + account=accounts, + cacert=controller.get('ca-cert'), + bakery_client=self.bakery_client_for_controller(controller_name), + specified_facades=specified_facades, + proxy=proxy, + ) + await self.connect(**kwargs) self.controller_name = controller_name self.controller_uuid = controller["uuid"] @@ -176,8 +187,7 @@ async def connect_model(self, model_name=None, **kwargs): # JujuData. kwargs.update(endpoint=endpoints, uuid=model_uuid, - username=account.get('user'), - password=account.get('password'), + account=account, cacert=controller.get('ca-cert'), bakery_client=self.bakery_client_for_controller(controller_name), proxy=proxy) diff --git a/juju/controller.py b/juju/controller.py index d1c4607af..2e46e22ef 100644 --- a/juju/controller.py +++ b/juju/controller.py @@ -139,11 +139,15 @@ async def connect(self, *args, **kwargs): await self.update_endpoints() async def update_endpoints(self): - info = await self.info() - self._connector._connection.endpoints = [ - (e, info.results[0].cacert) - for e in info.results[0].addresses - ] + try: + info = await self.info() + self._connector._connection.endpoints = [ + (e, info.results[0].cacert) + for e in info.results[0].addresses + ] + except errors.JujuPermissionError: + log.warning("This user doesn't have at least read access to the controller model, so endpoints are not updated after connection.") + pass async def connect_current(self): """ @@ -281,6 +285,8 @@ async def info(self): """ log.debug('Getting information') uuids = await self.model_uuids() + if 'controller' not in uuids: + raise errors.JujuPermissionError('Requires access to controller model.') controller_facade = client.ControllerFacade.from_connection(self.connection()) params = [client.Entity(tag.model(uuids["controller"]))] return await controller_facade.ControllerAPIInfoForModels(entities=params) diff --git a/juju/errors.py b/juju/errors.py index 61026dcee..a246aaa9c 100644 --- a/juju/errors.py +++ b/juju/errors.py @@ -82,6 +82,10 @@ class JujuUnitError(JujuError): pass +class JujuPermissionError(JujuError): + pass + + class JujuBackupError(JujuError): pass