From: George Kraft Date: Thu, 28 Sep 2017 18:29:36 +0000 (-0500) Subject: Make Application.upgrade_charm upgrade resources (#158) X-Git-Tag: 0.6.1~3 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=ce681706b825bf60060e2fca41037670b9945006;p=osm%2FN2VC.git Make Application.upgrade_charm upgrade resources (#158) * Add Resource to client overrides due to missing 'origin' field * Make Application.upgrade_charm upgrade resources * Add test_upgrade_charm_resource * upgrade_charm: Only call the charm store once --- diff --git a/juju/application.py b/juju/application.py index 8719a62..0d6c2d9 100644 --- a/juju/application.py +++ b/juju/application.py @@ -342,8 +342,13 @@ class Application(model.ModelEntity): raise ValueError("switch and revision are mutually exclusive") client_facade = client.ClientFacade.from_connection(self.connection) + resources_facade = client.ResourcesFacade.from_connection( + self.connection) app_facade = client.ApplicationFacade.from_connection(self.connection) + charmstore = self.model.charmstore + charmstore_entity = None + if switch is not None: charm_url = switch if not charm_url.startswith('cs:'): @@ -354,18 +359,65 @@ class Application(model.ModelEntity): if revision is not None: charm_url = "%s-%d" % (charm_url, revision) else: - charmstore = self.model.charmstore - entity = await charmstore.entity(charm_url, channel=channel) - charm_url = entity['Id'] + charmstore_entity = await charmstore.entity(charm_url, + channel=channel) + charm_url = charmstore_entity['Id'] if charm_url == self.data['charm-url']: raise JujuError('already running charm "%s"' % charm_url) + # Update charm await client_facade.AddCharm( url=charm_url, channel=channel ) + # Update resources + if not charmstore_entity: + charmstore_entity = await charmstore.entity(charm_url, + channel=channel) + store_resources = charmstore_entity['Meta']['resources'] + + request_data = [client.Entity(self.tag)] + response = await resources_facade.ListResources(request_data) + existing_resources = { + resource.name: resource + for resource in response.results[0].resources + } + + resources_to_update = [ + resource for resource in store_resources + if resource['Name'] not in existing_resources or + existing_resources[resource['Name']].origin != 'upload' + ] + + if resources_to_update: + request_data = [ + client.CharmResource( + description=resource.get('Description'), + fingerprint=resource['Fingerprint'], + name=resource['Name'], + path=resource['Path'], + revision=resource['Revision'], + size=resource['Size'], + type_=resource['Type'], + origin='store', + ) for resource in resources_to_update + ] + response = await resources_facade.AddPendingResources( + self.tag, + charm_url, + request_data + ) + pending_ids = response.pending_ids + resource_ids = { + resource['Name']: id + for resource, id in zip(resources_to_update, pending_ids) + } + else: + resource_ids = None + + # Update application await app_facade.SetCharm( application=self.entity_id, channel=channel, @@ -374,7 +426,7 @@ class Application(model.ModelEntity): config_settings_yaml=None, force_series=force_series, force_units=force_units, - resource_ids=None, + resource_ids=resource_ids, storage_constraints=None ) diff --git a/juju/client/overrides.py b/juju/client/overrides.py index f439adb..93c41c1 100644 --- a/juju/client/overrides.py +++ b/juju/client/overrides.py @@ -11,6 +11,7 @@ __all__ = [ 'Number', 'Binary', 'ConfigValue', + 'Resource', ] __patches__ = [ @@ -273,3 +274,26 @@ class ConfigValue(_definitions.ConfigValue): return '<{} source={} value={}>'.format(type(self).__name__, repr(self.source), repr(self.value)) + +class Resource(Type): + _toSchema = {'application': 'application', 'charmresource': 'CharmResource', 'id_': 'id', 'pending_id': 'pending-id', 'timestamp': 'timestamp', 'username': 'username', 'name': 'name', 'origin': 'origin'} + _toPy = {'CharmResource': 'charmresource', 'application': 'application', 'id': 'id_', 'pending-id': 'pending_id', 'timestamp': 'timestamp', 'username': 'username', 'name': 'name', 'origin': 'origin'} + def __init__(self, charmresource=None, application=None, id_=None, pending_id=None, timestamp=None, username=None, name=None, origin=None, **unknown_fields): + ''' + charmresource : CharmResource + application : str + id_ : str + pending_id : str + timestamp : str + username : str + name: str + origin : str + ''' + self.charmresource = CharmResource.from_json(charmresource) if charmresource else None + self.application = application + self.id_ = id_ + self.pending_id = pending_id + self.timestamp = timestamp + self.username = username + self.name = name + self.origin = origin diff --git a/tests/integration/test_application.py b/tests/integration/test_application.py index 1a4fcaa..7b780da 100644 --- a/tests/integration/test_application.py +++ b/tests/integration/test_application.py @@ -1,3 +1,4 @@ +import asyncio import pytest from .. import base @@ -92,3 +93,32 @@ async def test_upgrade_charm_switch(event_loop): assert app.data['charm-url'] == 'cs:ubuntu-0' await app.upgrade_charm(switch='ubuntu-8') assert app.data['charm-url'] == 'cs:ubuntu-8' + + +@base.bootstrapped +@pytest.mark.asyncio +async def test_upgrade_charm_resource(event_loop): + async with base.CleanModel() as model: + app = await model.deploy('cs:~cynerva/upgrade-charm-resource-test-1') + + def units_ready(): + if not app.units: + return False + unit = app.units[0] + return unit.workload_status == 'active' and \ + unit.agent_status == 'idle' + + await asyncio.wait_for(model.block_until(units_ready), timeout=480) + unit = app.units[0] + expected_message = 'I have no resource.' + assert unit.workload_status_message == expected_message + + await app.upgrade_charm(revision=2) + await asyncio.wait_for( + model.block_until( + lambda: unit.workload_status_message != 'I have no resource.' + ), + timeout=60 + ) + expected_message = 'My resource: I am the resource.' + assert app.units[0].workload_status_message == expected_message