Skip to content

Commit d813202

Browse files
Ensure we can talk to old controllers
The following changes ensures that if we talk to older controllers we can correctly deploy bundles as well.
1 parent e8129af commit d813202

5 files changed

Lines changed: 63 additions & 46 deletions

File tree

examples/deploy_bundle.py

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,41 @@
66
3. Destroys the units and applications
77
88
"""
9+
from juju.controller import Controller
910
from juju import loop
10-
from juju.model import Model
1111

1212

1313
async def main():
14-
model = Model()
15-
print('Connecting to model')
16-
# Connect to current model with current user, per Juju CLI
17-
await model.connect()
18-
19-
try:
20-
print('Deploying bundle')
21-
applications = await model.deploy(
22-
'cs:~juju-qa/bundle/basic-0',
23-
channel='beta',
24-
)
25-
26-
print('Waiting for active')
27-
await model.block_until(
28-
lambda: all(unit.workload_status == 'active'
29-
for application in applications for unit in application.units))
30-
print("Successfully deployed!")
31-
print('Removing bundle')
32-
for application in applications:
33-
await application.remove()
34-
finally:
35-
print('Disconnecting from model')
36-
await model.disconnect()
37-
print("Success")
14+
controller = Controller()
15+
# connect to current controller with current user, per Juju CLI
16+
await controller.connect()
17+
18+
bundles = [('juju-qa-bundle-test', None), ('cs:~juju-qa/bundle/basic-0', 'beta')]
19+
for i in range(len(bundles)):
20+
deployment = bundles[i]
21+
model = await controller.add_model('model{}'.format(i))
22+
23+
try:
24+
print('Deploying bundle')
25+
applications = await model.deploy(
26+
deployment[0],
27+
channel=deployment[1],
28+
)
29+
30+
print('Waiting for active')
31+
await model.block_until(
32+
lambda: all(unit.workload_status == 'active'
33+
for application in applications for unit in application.units))
34+
print("Successfully deployed!")
35+
print('Removing bundle')
36+
for application in applications:
37+
await application.remove()
38+
finally:
39+
print('Disconnecting from model')
40+
await model.disconnect()
41+
print("Success")
42+
43+
await controller.disconnect()
3844

3945

4046
if __name__ == '__main__':

juju/bundle.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from .errors import JujuError
1717
from .origin import Channel
1818
from .url import Schema, URL
19+
from .version import LTS_RELEASES
1920

2021
log = logging.getLogger(__name__)
2122

@@ -230,7 +231,6 @@ async def _resolve_charms(self):
230231
if is_local_charm(spec['charm']):
231232
spec.charm = self.model.applications[name]
232233
continue
233-
234234
if spec['charm'] == app.charm_url:
235235
continue
236236

@@ -239,14 +239,13 @@ async def _resolve_charms(self):
239239
if is_local_charm(spec['charm']):
240240
continue
241241

242+
charm_url = URL.parse(spec['charm'])
243+
channel = None
244+
track, risk = '', ''
245+
if 'channel' in spec:
246+
channel = Channel.parse(spec['channel'])
247+
track, risk = channel.track, channel.risk
242248
if self.charms_facade is not None:
243-
charm_url = URL.parse(spec['charm'])
244-
channel = None
245-
track, risk = '', ''
246-
if 'channel' in spec:
247-
channel = Channel.parse(spec['channel'])
248-
track, risk = channel.track, channel.risk
249-
250249
if cons is not None and cons['arch'] != '':
251250
architecture = cons['arch']
252251
else:
@@ -259,13 +258,15 @@ async def _resolve_charms(self):
259258
charm_url, charm_origin = await self.model._resolve_charm(charm_url, origin)
260259

261260
spec['charm'] = str(charm_url)
262-
263-
if str(channel) not in self.origins:
264-
self.origins[str(charm_url)] = {}
265-
self.origins[str(charm_url)][str(channel)] = charm_origin
266261
else:
267-
await self.client_facade.ResolveCharms(references=[spec['charm']])
268-
# TODO (stickupkid): Ensure that this works as expected.
262+
results = await self.model.charmstore.entity(str(charm_url))
263+
charm_origin = client.CharmOrigin(source="charm-store",
264+
risk=risk,
265+
track=track)
266+
267+
if str(channel) not in self.origins:
268+
self.origins[str(charm_url)] = {}
269+
self.origins[str(charm_url)][str(channel)] = charm_origin
269270

270271
async def execute_plan(self):
271272
await self._resolve_charms()
@@ -471,7 +472,7 @@ async def run(self, context):
471472
resources = {}
472473

473474
channel = None
474-
if self.channel is not None:
475+
if self.channel is not None and self.channel != "":
475476
channel = Channel.parse(self.channel).normalize()
476477

477478
origin = context.origins[str(url)][str(channel)]
@@ -575,6 +576,7 @@ async def run(self, context):
575576
log.debug('Adding %s', entity_id)
576577
await context.client_facade.AddCharm(channel=None, url=entity_id, force=False)
577578
identifier = entity_id
579+
origin = client.CharmOrigin(source="charm-store", risk="stable")
578580

579581
elif Schema.CHARM_HUB.matches(url.schema):
580582
ch = Channel('latest', 'stable')

juju/model.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from .placement import parse as parse_placement
4040
from .tag import application as application_tag
4141
from .url import URL, Schema
42+
from .version import DEFAULT_ARCHITECTURE
4243

4344
log = logging.getLogger(__name__)
4445

@@ -1602,7 +1603,7 @@ async def _resolve_architecture(self, url):
16021603
if 'arch' in constraints:
16031604
return constraints['arch']
16041605

1605-
return "amd64"
1606+
return DEFAULT_ARCHITECTURE
16061607

16071608
async def _add_store_resources(self, application, entity_url,
16081609
overrides=None, entity=None):

juju/url.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,18 @@ def parse(s):
5252
return c
5353

5454
def with_revision(self, rev):
55-
return URL(self.schema, self.user, self.name, rev, self.series)
55+
return URL(self.schema, self.user, self.name, rev, self.series, self.architecture)
56+
57+
def with_series(self, series):
58+
return URL(self.schema, self.user, self.name, self.revision, series, self.architecture)
5659

5760
def path(self):
5861
parts = []
59-
if self.user:
62+
if self.user is not None:
6063
parts.append("~{}".format(self.user))
61-
if self.architecture:
64+
if self.architecture is not None:
6265
parts.append(self.architecture)
63-
if self.series:
66+
if self.series is not None:
6467
parts.append(self.series)
6568
if self.revision is not None and self.revision >= 0:
6669
parts.append("{}-{}".format(self.name, self.revision))
@@ -74,7 +77,8 @@ def __eq__(self, other):
7477
self.user == other.user and \
7578
self.name == other.name and \
7679
self.revision == other.revision and \
77-
self.series == other.series
80+
self.series == other.series and \
81+
self.architecture == other.architecture
7882
return False
7983

8084
def __str__(self):

juju/version.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
LTS_RELEASES = ["focal", "bionic", "xenial", "trusty", "precise"]
3+
4+
DEFAULT_ARCHITECTURE = 'amd64'

0 commit comments

Comments
 (0)