Skip to content

Commit 1a48d5b

Browse files
authored
Merge branch 'master' into fix/machine_ssh_cherry_picked
2 parents 0145b73 + f0f0ba1 commit 1a48d5b

13 files changed

Lines changed: 88 additions & 47 deletions

File tree

MANIFEST.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
include *.py CONTRIBUTORS LICENSE README.rst VERSION
1+
include *.py CONTRIBUTORS LICENSE README.rst
22
recursive-include juju *.py
33
recursive-include examples *.py
44
recursive-include docs *.rst

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
BIN := .tox/py3/bin
22
PY := $(BIN)/python3
33
PIP := $(BIN)/pip3
4-
VERSION=$(shell cat VERSION)
4+
VERSION := $(shell $(PY) -c "from juju.version import CLIENT_VERSION; print(CLIENT_VERSION)")
55

66
.PHONY: clean
77
clean:

VERSION

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/changelog.rst

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,35 @@
11
Changelog
22
---------
33

4-
3.3.0.0
4+
3.3.1.1
55
^^^^^^^
66

7+
Thursday 15th Feb 2024
8+
79
## What's Changed
810

11+
This is a patch release for fixing some build problems in the 3.3.1.0 release that rendered it unusable in some scenarios.
12+
13+
* Resolve build problems in 3.3.1.0 by @cderici in https://github.com/juju/python-libjuju/pull/1026
14+
15+
3.3.1.0
16+
^^^^^^^
17+
18+
Thursday 8th Feb 2024
19+
20+
* Remove paramiko upper-bound by @gboutry in https://github.com/juju/python-libjuju/pull/1005
21+
* Remove explicit passing of event_loop into tests by @cderici in https://github.com/juju/python-libjuju/pull/1006
22+
* chore: remove the upper restrictions on the websockets dependency by @tonyandrewmeyer in https://github.com/juju/python-libjuju/pull/1007
23+
* Target ceiling version by @cderici in https://github.com/juju/python-libjuju/pull/1008
24+
* Make it easier to run tests using `make` by @cderici in https://github.com/juju/python-libjuju/pull/1012
25+
* Avoid installing signal handlers to the event loop by @cderici in https://github.com/juju/python-libjuju/pull/1014
26+
* feat: remove app block until done by @yanksyoon in https://github.com/juju/python-libjuju/pull/1017
27+
* feat: remove app timeout by @yanksyoon in https://github.com/juju/python-libjuju/pull/1018
28+
* Forward port latest changes from 2.9 onto 3.x by @cderici in https://github.com/juju/python-libjuju/pull/1022
29+
30+
3.3.0.0
31+
^^^^^^^
32+
933
The main contribution of this release is the user secrets that's released as a part of Juju 3.3.
1034

1135
Thursday 30th Nov 2023

docs/conf.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@
2121
from pathlib import Path
2222

2323
here = Path(__file__).absolute().parent
24-
version = (here.parent / 'VERSION').read_text().strip()
24+
2525

2626
# If extensions (or modules to document with autodoc) are in another directory,
2727
# add these directories to sys.path here. If the directory is relative to the
2828
# documentation root, use os.path.abspath to make it absolute, like shown here.
2929
sys.path.insert(0, os.path.abspath('..'))
3030

31+
from juju.version import CLIENT_VERSION
32+
version = CLIENT_VERSION
33+
3134
# -- General configuration ------------------------------------------------
3235

3336
# If your documentation needs a minimal Sphinx version, state it here.

docs/requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ paramiko
1212
macaroonbakery
1313
toposort
1414
python-dateutil
15-
kubernetes
15+
kubernetes
16+
packaging

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)