Skip to content

Commit 36f350e

Browse files
committed
Implement series selector for charm resolution
This selector will be used after the ResolveCharms api call, and use the supported series and the base information returned to select the appropriate series to construct the correct base for the charm. Then it's given to the AddCharm in normal the deploy process.
1 parent 9670a5e commit 36f350e

1 file changed

Lines changed: 99 additions & 1 deletion

File tree

juju/utils.py

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from . import jasyncio, origin, errors
1313
from .client import client
14+
from .errors import JujuError
1415

1516

1617
async def execute_process(*cmd, log=None):
@@ -412,7 +413,104 @@ def parse_base_arg(base):
412413
"""
413414
client.CharmBase()
414415
if type(base) != str or "@" not in base:
415-
raise errors.JujuError("expected base string to contain os and channel separated by '@'")
416+
raise errors.JujuError(f"expected base string to contain os and channel separated by '@', got : {base}")
416417

417418
name, channel = base.split('@')
418419
return client.Base(name=name, channel=channel)
420+
421+
422+
DEFAULT_SUPPORTED_LTS = 'jammy'
423+
DEFAULT_SUPPORTED_LTS_BASE = client.Base(channel='22.04', name='ubuntu')
424+
425+
426+
def base_channel_from_series(track, risk, series=None):
427+
return origin.Channel(track=track, risk=risk).normalize().compute_base_channel(series=series)
428+
429+
430+
def get_os_from_series(series=None):
431+
if not series or series in UBUNTU_SERIES:
432+
return 'ubuntu'
433+
raise JujuError(f'os for the series {series} needs to be added')
434+
435+
436+
def get_base_from_origin_or_channel(origin_or_channel, series=None):
437+
channel = base_channel_from_series(origin_or_channel.track, origin_or_channel.risk, series)
438+
os_name = get_os_from_series(series)
439+
return client.Base(channel=channel, name=os_name)
440+
441+
442+
def series_for_charm(requested_series, supported_series):
443+
"""series_for_charm takes a requested series and a list of series supported by a
444+
charm and returns the series which is relevant.
445+
If the requested series is empty, then the first supported series is used,
446+
otherwise the requested series is validated against the supported series.
447+
"""
448+
if len(supported_series) == 1 and supported_series[0] == '':
449+
raise JujuError("invalid supported series reported by charm : ['']")
450+
if len(supported_series) == 0:
451+
if requested_series == '':
452+
raise JujuError("missing series")
453+
return requested_series
454+
455+
# use the charm default
456+
if requested_series == '':
457+
return supported_series[-1]
458+
459+
for s in supported_series:
460+
if requested_series == s:
461+
return requested_series
462+
raise JujuError(f'requested series {requested_series} is not among the supported series {supported_series}')
463+
464+
465+
def user_requested(series_arg, supported_series, force):
466+
series = series_for_charm(series_arg, supported_series)
467+
if force:
468+
series = series_arg
469+
# Todo (cderici): validate the series with workload_series to see if juju is supporting that
470+
return series
471+
472+
473+
def series_selector(series_arg='', charm_url=None, model_config=None, supported_series=[], force=False):
474+
"""
475+
series_selector corresponds to the CharmSeries() in
476+
https://github.com/juju/juju/blob/develop/core/charm/series_selector.go
477+
478+
determines what series to use with a charm.
479+
Order of preference is:
480+
- user requested with --series or defined by bundle when deploying
481+
- user requested in charm's url (e.g. juju deploy jammy/ubuntu)
482+
- model default, if set, acts like --series
483+
- default from charm metadata supported series / series in url
484+
- default LTS
485+
"""
486+
487+
# User has requested a series with --series.
488+
if series_arg:
489+
return user_requested(series_arg, supported_series, force)
490+
491+
# User specified a series in the charm URL, e.g.
492+
# juju deploy precise/ubuntu.
493+
if charm_url and charm_url.series:
494+
return user_requested(charm_url.series, supported_series, force)
495+
496+
# No series explicitly requested by the user.
497+
# Use model default series, if explicitly set and supported by the charm.
498+
if model_config and model_config['default-base'].value:
499+
default_base = model_config['default-base'].value
500+
base = parse_base_arg(default_base)
501+
series = base_channel_to_series(base.channel)
502+
return user_requested(series, supported_series, force)
503+
504+
# Next fall back to the charm's list of series, filtered to what's supported
505+
# by Juju. Preserve the order of the supported series from the charm
506+
# metadata, as the order could be out of order compared to Ubuntu series
507+
# order (precise, xenial, bionic, trusty, etc).
508+
try:
509+
# TODO (cderici): restrict the supported_series with JujuSupportedSeries
510+
return user_requested('', supported_series, force)
511+
except JujuError:
512+
pass
513+
514+
# Charm hasn't specified a default (likely due to being a local charm
515+
# deployed by path). Last chance, best we can do is default to LTS.
516+
return DEFAULT_SUPPORTED_LTS

0 commit comments

Comments
 (0)