Skip to content

Commit dd93886

Browse files
authored
Merge pull request #1022 from cderici/forward-ports-from-29
#1022 #### Description This brings onto the 3.x track some of the latest fixes from to the 2.9 track. Here're the details: * Fix for #989 from #990 * Fix for #1001 from #1002 * Fix for #998 from #1003 #### QA Steps No QA needed for #990. For 1002 and 1003 please refer to their QA steps. Though they are very related so I'd expect the QA for both of them can be done in one fell swoop. * #1002 * #1003 All CI tests need to pass (there's still some known intermittent ones in there).
2 parents 16149db + fedeb48 commit dd93886

4 files changed

Lines changed: 49 additions & 27 deletions

File tree

juju/client/connection.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,9 @@ async def close(self, to_reconnect=False):
470470

471471
async def _recv(self, request_id):
472472
if not self.is_open:
473-
raise websockets.exceptions.ConnectionClosed(0, 'websocket closed')
473+
raise websockets.exceptions.ConnectionClosed(
474+
websockets.frames.Close(websockets.frames.CloseCode.NORMAL_CLOSURE,
475+
'websocket closed'))
474476
try:
475477
return await self.messages.get(request_id)
476478
except GeneratorExit:
@@ -641,7 +643,8 @@ async def rpc(self, msg, encoder=None):
641643
if self.monitor.status == Monitor.DISCONNECTED:
642644
# closed cleanly; shouldn't try to reconnect
643645
raise websockets.exceptions.ConnectionClosed(
644-
0, 'websocket closed')
646+
websockets.frames.Close(websockets.frames.CloseCode.NORMAL_CLOSURE,
647+
'websocket closed'))
645648
try:
646649
await self._ws.send(outgoing)
647650
break

juju/client/connector.py

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ async def connect(self, **kwargs):
8585
# connected to.
8686
if self._connection:
8787
await self._connection.close()
88+
89+
account = kwargs.pop('account', {})
90+
# Prioritize the username and password that user provided
91+
# If not enough, try to patch it with info from accounts.yaml
92+
if 'username' not in kwargs and account.get('user'):
93+
kwargs.update(username=account.get('user'))
94+
if 'password' not in kwargs and account.get('password'):
95+
kwargs.update(password=account.get('password'))
96+
97+
if not ({'username', 'password'}.issubset(kwargs)):
98+
required = {'username', 'password'}.difference(kwargs)
99+
raise ValueError(f'Some authentication parameters are required : {",".join(required)}')
88100
self._connection = await Connection.connect(**kwargs)
89101

90102
# Check if we support the target controller
@@ -117,7 +129,7 @@ async def disconnect(self, entity):
117129
await self._log_connection.close()
118130
self._log_connection = None
119131

120-
async def connect_controller(self, controller_name=None, specified_facades=None):
132+
async def connect_controller(self, controller_name=None, specified_facades=None, **kwargs):
121133
"""Connect to a controller by name. If the name is empty, it
122134
connect to the current controller.
123135
"""
@@ -130,16 +142,16 @@ async def connect_controller(self, controller_name=None, specified_facades=None)
130142

131143
proxy = proxy_from_config(controller.get("proxy-config", None))
132144

133-
await self.connect(
134-
endpoint=endpoints,
135-
uuid=None,
136-
username=accounts.get("user"),
137-
password=accounts.get("password"),
138-
cacert=controller.get("ca-cert"),
139-
bakery_client=self.bakery_client_for_controller(controller_name),
140-
specified_facades=specified_facades,
141-
proxy=proxy,
142-
)
145+
kwargs.update(endpoint=endpoints,
146+
uuid=None,
147+
account=accounts,
148+
cacert=controller.get('ca-cert'),
149+
bakery_client=self.bakery_client_for_controller(controller_name),
150+
specified_facades=specified_facades,
151+
proxy=proxy,
152+
)
153+
await self.connect(**kwargs)
154+
self.controller_name = controller_name
143155
self.controller_uuid = controller["uuid"]
144156

145157
async def connect_model(self, _model_name=None, **kwargs):
@@ -184,15 +196,12 @@ async def connect_model(self, _model_name=None, **kwargs):
184196

185197
# TODO remove the need for base.CleanModel to subclass
186198
# JujuData.
187-
kwargs.update(
188-
endpoint=endpoints,
189-
uuid=model_uuid,
190-
username=account.get("user"),
191-
password=account.get("password"),
192-
cacert=controller.get("ca-cert"),
193-
bakery_client=self.bakery_client_for_controller(controller_name),
194-
proxy=proxy,
195-
)
199+
kwargs.update(endpoint=endpoints,
200+
uuid=model_uuid,
201+
account=account,
202+
cacert=controller.get('ca-cert'),
203+
bakery_client=self.bakery_client_for_controller(controller_name),
204+
proxy=proxy)
196205
await self.connect(**kwargs)
197206
# TODO this might be a good spot to trigger refreshing the
198207
# local cache (the connection to the model might help)

juju/controller.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,15 @@ async def connect(self, *args, **kwargs):
140140
await self.update_endpoints()
141141

142142
async def update_endpoints(self):
143-
info = await self.info()
144-
self._connector._connection.endpoints = [
145-
(e, info.results[0].cacert)
146-
for e in info.results[0].addresses
147-
]
143+
try:
144+
info = await self.info()
145+
self._connector._connection.endpoints = [
146+
(e, info.results[0].cacert)
147+
for e in info.results[0].addresses
148+
]
149+
except errors.JujuPermissionError:
150+
log.warning("This user doesn't have at least read access to the controller model, so endpoints are not updated after connection.")
151+
pass
148152

149153
async def connect_current(self):
150154
"""
@@ -288,6 +292,8 @@ async def info(self):
288292
"""
289293
log.debug('Getting information')
290294
uuids = await self.model_uuids()
295+
if 'controller' not in uuids:
296+
raise errors.JujuPermissionError('Requires access to controller model.')
291297
controller_facade = client.ControllerFacade.from_connection(self.connection())
292298
params = [client.Entity(tag.model(uuids["controller"]))]
293299
return await controller_facade.ControllerAPIInfoForModels(entities=params)

juju/errors.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ class JujuUnitError(JujuError):
8686
pass
8787

8888

89+
class JujuPermissionError(JujuError):
90+
pass
91+
92+
8993
class JujuBackupError(JujuError):
9094
pass
9195

0 commit comments

Comments
 (0)