Skip to content

Commit b880396

Browse files
committed
Adds resource support for charmhub deployments
1 parent ef05ad8 commit b880396

4 files changed

Lines changed: 96 additions & 7 deletions

File tree

examples/charmhub_deploy.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
This example:
3+
4+
1. Connects to the current model
5+
2. Deploy a charm and waits until it reports itself active
6+
3. Destroys the unit and application
7+
8+
"""
9+
from juju import loop
10+
from juju.model import Model
11+
12+
13+
async def main():
14+
model = Model()
15+
print('Connecting to model')
16+
await model.connect()
17+
18+
try:
19+
print('Deploying ')
20+
application = await model.deploy(
21+
'ch:snappass-test',
22+
application_name='snappass'
23+
)
24+
25+
print('Waiting for active')
26+
await model.block_until(
27+
lambda: all(unit.workload_status == 'active'
28+
for unit in application.units))
29+
30+
finally:
31+
print('Disconnecting from model')
32+
await model.disconnect()
33+
34+
if __name__ == '__main__':
35+
loop.run(main())

juju/client/overrides.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ class ResourcesFacade(Type):
6363
"""
6464

6565
@ReturnMapping(_client.AddPendingResourcesResult)
66-
async def AddPendingResources(self, application_tag="", charm_url="", resources=None):
66+
async def AddPendingResources(self,
67+
application_tag="",
68+
charm_url="",
69+
charm_origin=None,
70+
resources=None):
6771
"""Fix the calling signature of AddPendingResources.
6872
6973
The ResourcesFacade doesn't conform to the standard facade pattern in
@@ -81,11 +85,12 @@ async def AddPendingResources(self, application_tag="", charm_url="", resources=
8185
_params = dict()
8286
msg = dict(type='Resources',
8387
request='AddPendingResources',
84-
version=1,
88+
version=2,
8589
params=_params)
8690
_params['tag'] = application_tag
8791
_params['url'] = charm_url
8892
_params['resources'] = resources
93+
_params['charm-origin'] = charm_origin
8994
reply = await self.rpc(msg)
9095
return reply
9196

juju/model.py

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,10 +1595,13 @@ async def deploy(
15951595
# XXX: we're dropping local resources here, but we don't
15961596
# actually support them yet anyway
15971597
if not res.is_local:
1598-
await self._add_charm(identifier, res.origin)
1598+
add_charm_res = await self._add_charm(identifier, res.origin)
1599+
1600+
if Schema.CHARM_HUB.matches(url.schema):
1601+
resources = await self._add_charmhub_resources(res.app_name,
1602+
identifier,
1603+
add_charm_res.charm_origin)
15991604

1600-
# TODO (stickupkid): Handle charmhub charms, for now we'll only
1601-
# handle charmstore charms.
16021605
if Schema.CHARM_STORE.matches(url.schema):
16031606
resources = await self._add_store_resources(res.app_name,
16041607
identifier)
@@ -1632,6 +1635,7 @@ async def deploy(
16321635
num_units=num_units,
16331636
placement=parse_placement(to),
16341637
devices=devices,
1638+
charm_origin=add_charm_res.charm_origin,
16351639
)
16361640

16371641
async def _add_charm(self, charm_url, origin):
@@ -1684,6 +1688,50 @@ async def _resolve_architecture(self, url):
16841688

16851689
return DEFAULT_ARCHITECTURE
16861690

1691+
async def _add_charmhub_resources(self, application,
1692+
entity_url,
1693+
origin,
1694+
overrides=None):
1695+
charm_facade = client.CharmsFacade.from_connection(self.connection())
1696+
res = await charm_facade.CharmInfo(entity_url)
1697+
1698+
resources = []
1699+
for resource in res.meta.resources.values():
1700+
resources.append({
1701+
'description': resource.description,
1702+
'name': resource.name,
1703+
'path': resource.path,
1704+
'type_': resource.type_,
1705+
'origin': 'store',
1706+
'revision': -1,
1707+
})
1708+
1709+
if overrides:
1710+
names = {r['name'] for r in resources}
1711+
unknown = overrides.keys() - names
1712+
if unknown:
1713+
raise JujuError('Unrecognized resource{}: {}'.format(
1714+
's' if len(unknown) > 1 else '',
1715+
', '.join(unknown)))
1716+
for resource in resources:
1717+
if resource['name'] in overrides:
1718+
resource['revision'] = overrides[resource['name']]
1719+
1720+
1721+
resources_facade = client.ResourcesFacade.from_connection(
1722+
self.connection())
1723+
response = await resources_facade.AddPendingResources(
1724+
application_tag=tag.application(application),
1725+
charm_url=entity_url,
1726+
charm_origin=origin,
1727+
resources=[client.CharmResource(**resource) for resource in resources],
1728+
)
1729+
1730+
resource_map = {resource['name']: pid
1731+
for resource, pid
1732+
in zip(resources, response.pending_ids)}
1733+
return resource_map
1734+
16871735
async def _add_store_resources(self, application, entity_url,
16881736
overrides=None):
16891737
entity = await self.charmstore.entity(entity_url,
@@ -1729,7 +1777,7 @@ async def _add_store_resources(self, application, entity_url,
17291777
async def _deploy(self, charm_url, application, series, config,
17301778
constraints, endpoint_bindings, resources, storage,
17311779
channel=None, num_units=None, placement=None,
1732-
devices=None):
1780+
devices=None, charm_origin=None):
17331781
"""Logic shared between `Model.deploy` and `BundleHandler.deploy`.
17341782
"""
17351783
log.info('Deploying %s', charm_url)
@@ -1747,6 +1795,7 @@ async def _deploy(self, charm_url, application, series, config,
17471795
application=application,
17481796
series=series,
17491797
channel=channel,
1798+
charm_origin=charm_origin,
17501799
config_yaml=config,
17511800
constraints=parse_constraints(constraints),
17521801
endpoint_bindings=endpoint_bindings,

tests/integration/test_application.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ async def test_deploy_charmstore_charm(event_loop):
107107
@pytest.mark.asyncio
108108
async def test_deploy_charmhub_charm(event_loop):
109109
async with base.CleanModel() as model:
110-
app = await model.deploy('hello-juju')
110+
app = await model.deploy('ch:hello-juju')
111111
await model.block_until(lambda: (len(app.units) > 0 and
112112
app.units[0].machine))
113113
assert 'hello-juju' in app.data['charm-url']

0 commit comments

Comments
 (0)