Skip to content

Commit c921b55

Browse files
authored
Merge branch 'main' into fix/list-secrets
2 parents 4930a4f + d0a18d3 commit c921b55

3 files changed

Lines changed: 90 additions & 20 deletions

File tree

juju/application.py

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
from .bundle import get_charm_series, is_local_charm
1313
from .client import client
1414
from .errors import JujuApplicationConfigError, JujuError
15-
from .origin import Channel, Source
15+
from .origin import Channel
1616
from .placement import parse as parse_placement
1717
from .relation import Relation
1818
from .status import derive_status
1919
from .url import URL
2020
from .utils import block_until
21+
from .version import DEFAULT_ARCHITECTURE
2122

2223
log = logging.getLogger(__name__)
2324

@@ -691,13 +692,15 @@ async def refresh(
691692
if charm_url_origin_result.error is not None:
692693
err = charm_url_origin_result.error
693694
raise JujuError(f'{err.code} : {err.message}')
694-
origin = charm_url_origin_result.charm_origin
695695

696+
current_origin = charm_url_origin_result.charm_origin
696697
if path is not None or (switch is not None and is_local_charm(switch)):
697-
await self.local_refresh(origin, force, force_series,
698+
await self.local_refresh(current_origin, force, force_series,
698699
force_units, path or switch, resources)
699700
return
700701

702+
origin = _refresh_origin(current_origin, channel, revision)
703+
701704
# If switch is not None at this point, that means it's a switch to a store charm
702705
charm_url = switch or charm_url_origin_result.url
703706
parsed_url = URL.parse(charm_url)
@@ -706,20 +709,6 @@ async def refresh(
706709
if parsed_url.schema is None:
707710
raise JujuError(f'A ch: or cs: schema is required for application refresh, given : {str(parsed_url)}')
708711

709-
if revision is not None:
710-
origin.revision = revision
711-
712-
# Make the source-specific changes to the origin/channel/url
713-
# (and also get the resources necessary to deploy the (destination) charm -- for later)
714-
origin.source = Source.CHARM_HUB.value
715-
if channel:
716-
ch = Channel.parse(channel).normalize()
717-
origin.risk = ch.risk
718-
origin.track = ch.track
719-
720-
charmhub = self.model.charmhub
721-
charm_resources = await charmhub.list_resources(charm_name)
722-
723712
# Resolve the given charm URLs with an optionally specified preferred channel.
724713
# Channel provided via CharmOrigin.
725714
resolved_charm_with_channel_results = await charms_facade.ResolveCharms(
@@ -761,8 +750,7 @@ async def refresh(
761750
else:
762751
_arg_res_filenames[res] = filename_or_rev
763752

764-
# Already prepped the charm_resources
765-
# Now get the existing resources from the ResourcesFacade
753+
# Get the existing resources from the ResourcesFacade
766754
request_data = [client.Entity(self.tag)]
767755
resources_facade = client.ResourcesFacade.from_connection(self.connection)
768756
response = await resources_facade.ListResources(entities=request_data)
@@ -771,6 +759,9 @@ async def refresh(
771759
for resource in response.results[0].resources
772760
}
773761

762+
charmhub = self.model.charmhub
763+
charm_resources = await charmhub.list_resources(charm_name)
764+
774765
# Compute the difference btw resources needed and the existing resources
775766
resources_to_update = []
776767
for resource in charm_resources:
@@ -917,6 +908,20 @@ async def get_metrics(self):
917908
return await self.model.get_metrics(self.tag)
918909

919910

911+
def _refresh_origin(current_origin: client.CharmOrigin, channel=None, revision=None) -> client.CharmOrigin:
912+
if channel is not None:
913+
channel = Channel.parse(channel).normalize()
914+
915+
return client.CharmOrigin(
916+
source=current_origin.source,
917+
track=channel.track if channel else current_origin.track,
918+
risk=channel.risk if channel else current_origin.risk,
919+
revision=revision if revision is not None else current_origin.revision,
920+
base=current_origin.base,
921+
architecture=current_origin.get('architecture', DEFAULT_ARCHITECTURE),
922+
)
923+
924+
920925
class ExposedEndpoint:
921926
"""ExposedEndpoint stores the list of CIDRs and space names which should be
922927
allowed access to the port ranges that the application has opened for a

tests/integration/test_application.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,18 @@ async def test_local_refresh():
286286
base=client.Base("20.04", "ubuntu"))
287287

288288

289+
@base.bootstrapped
290+
@pytest.mark.asyncio
291+
async def test_refresh_revision():
292+
async with base.CleanModel() as model:
293+
app = await model.deploy('juju-qa-test', channel="latest/stable", revision=23)
294+
# NOTE: juju-qa-test revision 26 has been released to this channel
295+
await app.refresh(revision=25)
296+
297+
charm_url = URL.parse(app.data['charm-url'])
298+
assert charm_url.revision == 25
299+
300+
289301
@base.bootstrapped
290302
@pytest.mark.asyncio
291303
async def test_trusted():

tests/unit/test_application.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
import asyncio
77

88
from juju.model import Model
9-
from juju.application import (Application, ExposedEndpoint)
9+
from juju.application import Application, ExposedEndpoint, _refresh_origin
1010
from juju.errors import JujuError
11+
from juju.client import client
12+
from juju.origin import Source
1113

1214

1315
class TestExposeApplication(unittest.IsolatedAsyncioTestCase):
@@ -177,3 +179,54 @@ async def test_refresh_mutually_exclusive_kwargs(self, mock_conn):
177179

178180
with self.assertRaises(ValueError):
179181
await app.refresh(switch="charm1", path="/path/to/charm2")
182+
183+
def test_refresh_origin(self):
184+
current_origin = client.CharmOrigin(
185+
source=str(Source.CHARM_HUB),
186+
track="latest",
187+
risk="stable",
188+
revision=100,
189+
base=client.Base("24.04", "ubuntu"),
190+
architecture="amd64",
191+
)
192+
193+
origin = _refresh_origin(current_origin, None, None)
194+
self.assertEqual(origin, current_origin)
195+
196+
origin = _refresh_origin(current_origin, None, 101)
197+
self.assertEqual(origin.revision, 101)
198+
# Check source, base & arch do not change
199+
self.assertEqual(origin.source, current_origin.source)
200+
self.assertEqual(origin.base, current_origin.base)
201+
self.assertEqual(origin.architecture, current_origin.architecture)
202+
203+
origin = _refresh_origin(current_origin, None, 0)
204+
self.assertEqual(origin.revision, 0)
205+
# Check source, base & arch do not change
206+
self.assertEqual(origin.source, current_origin.source)
207+
self.assertEqual(origin.base, current_origin.base)
208+
self.assertEqual(origin.architecture, current_origin.architecture)
209+
210+
origin = _refresh_origin(current_origin, "12/edge", None)
211+
self.assertEqual(origin.track, "12")
212+
self.assertEqual(origin.risk, "edge")
213+
# Check source, base & arch do not change
214+
self.assertEqual(origin.source, current_origin.source)
215+
self.assertEqual(origin.base, current_origin.base)
216+
self.assertEqual(origin.architecture, current_origin.architecture)
217+
218+
def test_refresh_origin_drops_id_hash(self):
219+
current_origin = client.CharmOrigin(
220+
source=str(Source.CHARM_HUB),
221+
track="latest",
222+
risk="stable",
223+
revision=100,
224+
base=client.Base("24.04", "ubuntu"),
225+
architecture="amd64",
226+
id_="id",
227+
hash_="hash",
228+
)
229+
230+
origin = _refresh_origin(current_origin, None, None)
231+
self.assertIsNone(origin.id_)
232+
self.assertIsNone(origin.hash_)

0 commit comments

Comments
 (0)