Skip to content

Commit 48570bb

Browse files
authored
Merge pull request #949 from cderici/deploy-from-repository-new-endpoint
#949 #### Description This allows pylibjuju to use the new `DeployFromRepository` endpoint, introduced in the `Application` facade `v19`. `PendingUploadResources` will be handled in a separate PR. This also fixes what juju/juju@22e3fc0#diff-cd1b6b10813a1b0ebe7fe9a04f11c401dfeec0574ffb00058bfec98b6bb1d255 seems to be breaking by returning a non-empty error list `(Pdb) self.plan.errors ['', '', '', '', '', '', '', '', '']` from `GetChangesMapArgs`. #### QA Steps There's two parts for QAing this. Making sure deploy still works for everything `< 3.3`. CI tests will cover most of that part of the QA, as we use deploy in almost every single integration test, and it's being tested against `latest/stable` (which as of today is `3.1.5`). So it is advisable to do the manual QA (see below) against juju `3.2`, just to be sure. Second part is obviously making sure that the deploy works for `3.3` with the new endpoint. To do that, I simply ```sh $ juju version 3.3-beta2-ubuntu-amd64 $ juju bootstrap localhost lxd33 && juju add-model test ``` Then just manually deployed the `ubuntu` charm using repl. ```python python -m asyncio asyncio REPL 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0] on linux Use "await" directly instead of "asyncio.run()". Type "help", "copyright", "credits" or "license" for more information. >>> import asyncio >>> from juju import model;m=model.Model();await m.connect();await m.deploy('ubuntu') <Application entity_id="ubuntu"> >>> exiting asyncio REPL... ``` All CI tests need to pass. #### Notes & Discussion JUJU-3637
2 parents 54c49e2 + 9672620 commit 48570bb

15 files changed

Lines changed: 55573 additions & 86 deletions

juju/bundle.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ async def fetch_plan(self, bundle_url, origin, overlays=[]):
298298
bundleurl=entity_id,
299299
yaml=yaml_data)
300300

301-
if self.plan.errors:
301+
if self.plan.errors and any(self.plan.errors):
302302
raise JujuError(self.plan.errors)
303303

304304
async def _download_bundle(self, charm_url, origin):

juju/client/_client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from juju.client._definitions import *
55

66

7-
from juju.client import _client7, _client1, _client3, _client4, _client2, _client17, _client6, _client11, _client10, _client5, _client9, _client18
7+
from juju.client import _client7, _client1, _client3, _client4, _client2, _client17, _client6, _client11, _client10, _client5, _client9, _client18, _client19
88

99

1010
CLIENTS = {
@@ -19,7 +19,8 @@
1919
"10": _client10,
2020
"5": _client5,
2121
"9": _client9,
22-
"18": _client18
22+
"18": _client18,
23+
"19": _client19
2324
}
2425

2526

juju/client/_client10.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ class MachineManagerFacade(Type):
140140
'type': 'array'},
141141
'cost': {'type': 'integer'},
142142
'cpu-cores': {'type': 'integer'},
143-
'deprecated': {'type': 'boolean'},
144143
'memory': {'type': 'integer'},
145144
'name': {'type': 'string'},
146145
'root-disk': {'type': 'integer'},

juju/client/_client19.py

Lines changed: 1813 additions & 0 deletions
Large diffs are not rendered by default.

juju/client/_client2.py

Lines changed: 354 additions & 0 deletions
Large diffs are not rendered by default.

juju/client/_client6.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ class BundleFacade(Type):
6060
'required': ['message', 'code'],
6161
'type': 'object'},
6262
'ExportBundleParams': {'additionalProperties': False,
63-
'properties': {'include-charm-defaults': {'type': 'boolean'}},
63+
'properties': {'include-charm-defaults': {'type': 'boolean'},
64+
'include-series': {'type': 'boolean'}},
6465
'type': 'object'},
6566
'StringResult': {'additionalProperties': False,
6667
'properties': {'error': {'$ref': '#/definitions/Error'},
@@ -109,23 +110,28 @@ class BundleFacade(Type):
109110

110111

111112
@ReturnMapping(StringResult)
112-
async def ExportBundle(self, include_charm_defaults=None):
113+
async def ExportBundle(self, include_charm_defaults=None, include_series=None):
113114
'''
114115
ExportBundle exports the current model configuration as bundle.
115116
116117
include_charm_defaults : bool
118+
include_series : bool
117119
Returns -> StringResult
118120
'''
119121
if include_charm_defaults is not None and not isinstance(include_charm_defaults, bool):
120122
raise Exception("Expected include_charm_defaults to be a bool, received: {}".format(type(include_charm_defaults)))
121123

124+
if include_series is not None and not isinstance(include_series, bool):
125+
raise Exception("Expected include_series to be a bool, received: {}".format(type(include_series)))
126+
122127
# map input types to rpc msg
123128
_params = dict()
124129
msg = dict(type='Bundle',
125130
request='ExportBundle',
126131
version=6,
127132
params=_params)
128133
_params['include-charm-defaults'] = include_charm_defaults
134+
_params['include-series'] = include_series
129135
reply = await self.rpc(msg)
130136
return reply
131137

juju/client/_client7.py

Lines changed: 646 additions & 1 deletion
Large diffs are not rendered by default.

juju/client/_definitions.py

Lines changed: 131 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9488,19 +9488,25 @@ def __init__(self, results=None, **unknown_fields):
94889488

94899489

94909490
class ExportBundleParams(Type):
9491-
_toSchema = {'include_charm_defaults': 'include-charm-defaults'}
9492-
_toPy = {'include-charm-defaults': 'include_charm_defaults'}
9493-
def __init__(self, include_charm_defaults=None, **unknown_fields):
9491+
_toSchema = {'include_charm_defaults': 'include-charm-defaults', 'include_series': 'include-series'}
9492+
_toPy = {'include-charm-defaults': 'include_charm_defaults', 'include-series': 'include_series'}
9493+
def __init__(self, include_charm_defaults=None, include_series=None, **unknown_fields):
94949494
'''
94959495
include_charm_defaults : bool
9496+
include_series : bool
94969497
'''
94979498
include_charm_defaults_ = include_charm_defaults
9499+
include_series_ = include_series
94989500

94999501
# Validate arguments against known Juju API types.
95009502
if include_charm_defaults_ is not None and not isinstance(include_charm_defaults_, bool):
95019503
raise Exception("Expected include_charm_defaults_ to be a bool, received: {}".format(type(include_charm_defaults_)))
95029504

9505+
if include_series_ is not None and not isinstance(include_series_, bool):
9506+
raise Exception("Expected include_series_ to be a bool, received: {}".format(type(include_series_)))
9507+
95039508
self.include_charm_defaults = include_charm_defaults_
9509+
self.include_series = include_series_
95049510
self.unknown_fields = unknown_fields
95059511

95069512

@@ -11062,6 +11068,30 @@ def __init__(self, args=None, **unknown_fields):
1106211068

1106311069

1106411070

11071+
class GrantRevokeUserSecretArg(Type):
11072+
_toSchema = {'applications': 'applications', 'uri': 'uri'}
11073+
_toPy = {'applications': 'applications', 'uri': 'uri'}
11074+
def __init__(self, applications=None, uri=None, **unknown_fields):
11075+
'''
11076+
applications : typing.Sequence[str]
11077+
uri : str
11078+
'''
11079+
applications_ = applications
11080+
uri_ = uri
11081+
11082+
# Validate arguments against known Juju API types.
11083+
if applications_ is not None and not isinstance(applications_, (bytes, str, list)):
11084+
raise Exception("Expected applications_ to be a Sequence, received: {}".format(type(applications_)))
11085+
11086+
if uri_ is not None and not isinstance(uri_, (bytes, str)):
11087+
raise Exception("Expected uri_ to be a str, received: {}".format(type(uri_)))
11088+
11089+
self.applications = applications_
11090+
self.uri = uri_
11091+
self.unknown_fields = unknown_fields
11092+
11093+
11094+
1106511095
class HardwareCharacteristics(Type):
1106611096
_toSchema = {'arch': 'arch', 'availability_zone': 'availability-zone', 'cpu_cores': 'cpu-cores', 'cpu_power': 'cpu-power', 'mem': 'mem', 'root_disk': 'root-disk', 'root_disk_source': 'root-disk-source', 'tags': 'tags', 'virt_type': 'virt-type'}
1106711097
_toPy = {'arch': 'arch', 'availability-zone': 'availability_zone', 'cpu-cores': 'cpu_cores', 'cpu-power': 'cpu_power', 'mem': 'mem', 'root-disk': 'root_disk', 'root-disk-source': 'root_disk_source', 'tags': 'tags', 'virt-type': 'virt_type'}
@@ -11717,14 +11747,13 @@ def __init__(self, characteristics=None, charm_profiles=None, display_name=None,
1171711747

1171811748

1171911749
class InstanceType(Type):
11720-
_toSchema = {'arches': 'arches', 'cost': 'cost', 'cpu_cores': 'cpu-cores', 'deprecated': 'deprecated', 'memory': 'memory', 'name': 'name', 'root_disk': 'root-disk', 'virt_type': 'virt-type'}
11721-
_toPy = {'arches': 'arches', 'cost': 'cost', 'cpu-cores': 'cpu_cores', 'deprecated': 'deprecated', 'memory': 'memory', 'name': 'name', 'root-disk': 'root_disk', 'virt-type': 'virt_type'}
11722-
def __init__(self, arches=None, cost=None, cpu_cores=None, deprecated=None, memory=None, name=None, root_disk=None, virt_type=None, **unknown_fields):
11750+
_toSchema = {'arches': 'arches', 'cost': 'cost', 'cpu_cores': 'cpu-cores', 'memory': 'memory', 'name': 'name', 'root_disk': 'root-disk', 'virt_type': 'virt-type'}
11751+
_toPy = {'arches': 'arches', 'cost': 'cost', 'cpu-cores': 'cpu_cores', 'memory': 'memory', 'name': 'name', 'root-disk': 'root_disk', 'virt-type': 'virt_type'}
11752+
def __init__(self, arches=None, cost=None, cpu_cores=None, memory=None, name=None, root_disk=None, virt_type=None, **unknown_fields):
1172311753
'''
1172411754
arches : typing.Sequence[str]
1172511755
cost : int
1172611756
cpu_cores : int
11727-
deprecated : bool
1172811757
memory : int
1172911758
name : str
1173011759
root_disk : int
@@ -11733,7 +11762,6 @@ def __init__(self, arches=None, cost=None, cpu_cores=None, deprecated=None, memo
1173311762
arches_ = arches
1173411763
cost_ = cost
1173511764
cpu_cores_ = cpu_cores
11736-
deprecated_ = deprecated
1173711765
memory_ = memory
1173811766
name_ = name
1173911767
root_disk_ = root_disk
@@ -11749,9 +11777,6 @@ def __init__(self, arches=None, cost=None, cpu_cores=None, deprecated=None, memo
1174911777
if cpu_cores_ is not None and not isinstance(cpu_cores_, int):
1175011778
raise Exception("Expected cpu_cores_ to be a int, received: {}".format(type(cpu_cores_)))
1175111779

11752-
if deprecated_ is not None and not isinstance(deprecated_, bool):
11753-
raise Exception("Expected deprecated_ to be a bool, received: {}".format(type(deprecated_)))
11754-
1175511780
if memory_ is not None and not isinstance(memory_, int):
1175611781
raise Exception("Expected memory_ to be a int, received: {}".format(type(memory_)))
1175711782

@@ -11767,7 +11792,6 @@ def __init__(self, arches=None, cost=None, cpu_cores=None, deprecated=None, memo
1176711792
self.arches = arches_
1176811793
self.cost = cost_
1176911794
self.cpu_cores = cpu_cores_
11770-
self.deprecated = deprecated_
1177111795
self.memory = memory_
1177211796
self.name = name_
1177311797
self.root_disk = root_disk_
@@ -18057,19 +18081,17 @@ def __init__(self, results=None, **unknown_fields):
1805718081

1805818082

1805918083
class PendingResourceUpload(Type):
18060-
_toSchema = {'filename': 'Filename', 'name': 'Name', 'pending_id': 'pending-id', 'type_': 'Type'}
18061-
_toPy = {'Filename': 'filename', 'Name': 'name', 'Type': 'type_', 'pending-id': 'pending_id'}
18062-
def __init__(self, filename=None, name=None, type_=None, pending_id=None, **unknown_fields):
18084+
_toSchema = {'filename': 'Filename', 'name': 'Name', 'type_': 'Type'}
18085+
_toPy = {'Filename': 'filename', 'Name': 'name', 'Type': 'type_'}
18086+
def __init__(self, filename=None, name=None, type_=None, **unknown_fields):
1806318087
'''
1806418088
filename : str
1806518089
name : str
1806618090
type_ : str
18067-
pending_id : str
1806818091
'''
1806918092
filename_ = filename
1807018093
name_ = name
1807118094
type__ = type_
18072-
pending_id_ = pending_id
1807318095

1807418096
# Validate arguments against known Juju API types.
1807518097
if filename_ is not None and not isinstance(filename_, (bytes, str)):
@@ -18081,13 +18103,9 @@ def __init__(self, filename=None, name=None, type_=None, pending_id=None, **unkn
1808118103
if type__ is not None and not isinstance(type__, (bytes, str)):
1808218104
raise Exception("Expected type__ to be a str, received: {}".format(type(type__)))
1808318105

18084-
if pending_id_ is not None and not isinstance(pending_id_, (bytes, str)):
18085-
raise Exception("Expected pending_id_ to be a str, received: {}".format(type(pending_id_)))
18086-
1808718106
self.filename = filename_
1808818107
self.name = name_
1808918108
self.type_ = type__
18090-
self.pending_id = pending_id_
1809118109
self.unknown_fields = unknown_fields
1809218110

1809318111

@@ -20904,18 +20922,18 @@ def __init__(self, charm_origin=None, reference=None, switch_charm=None, **unkno
2090420922

2090520923

2090620924
class ResolveCharmWithChannelResult(Type):
20907-
_toSchema = {'charm_origin': 'charm-origin', 'error': 'error', 'supported_series': 'supported-series', 'url': 'url'}
20908-
_toPy = {'charm-origin': 'charm_origin', 'error': 'error', 'supported-series': 'supported_series', 'url': 'url'}
20909-
def __init__(self, charm_origin=None, error=None, supported_series=None, url=None, **unknown_fields):
20925+
_toSchema = {'charm_origin': 'charm-origin', 'error': 'error', 'supported_bases': 'supported-bases', 'url': 'url'}
20926+
_toPy = {'charm-origin': 'charm_origin', 'error': 'error', 'supported-bases': 'supported_bases', 'url': 'url'}
20927+
def __init__(self, charm_origin=None, error=None, supported_bases=None, url=None, **unknown_fields):
2091020928
'''
2091120929
charm_origin : CharmOrigin
2091220930
error : Error
20913-
supported_series : typing.Sequence[str]
20931+
supported_bases : typing.Sequence[~Base]
2091420932
url : str
2091520933
'''
2091620934
charm_origin_ = CharmOrigin.from_json(charm_origin) if charm_origin else None
2091720935
error_ = Error.from_json(error) if error else None
20918-
supported_series_ = supported_series
20936+
supported_bases_ = [Base.from_json(o) for o in supported_bases or []]
2091920937
url_ = url
2092020938

2092120939
# Validate arguments against known Juju API types.
@@ -20925,15 +20943,15 @@ def __init__(self, charm_origin=None, error=None, supported_series=None, url=Non
2092520943
if error_ is not None and not isinstance(error_, (dict, Error)):
2092620944
raise Exception("Expected error_ to be a Error, received: {}".format(type(error_)))
2092720945

20928-
if supported_series_ is not None and not isinstance(supported_series_, (bytes, str, list)):
20929-
raise Exception("Expected supported_series_ to be a Sequence, received: {}".format(type(supported_series_)))
20946+
if supported_bases_ is not None and not isinstance(supported_bases_, (bytes, str, list)):
20947+
raise Exception("Expected supported_bases_ to be a Sequence, received: {}".format(type(supported_bases_)))
2093020948

2093120949
if url_ is not None and not isinstance(url_, (bytes, str)):
2093220950
raise Exception("Expected url_ to be a str, received: {}".format(type(url_)))
2093320951

2093420952
self.charm_origin = charm_origin_
2093520953
self.error = error_
20936-
self.supported_series = supported_series_
20954+
self.supported_bases = supported_bases_
2093720955
self.url = url_
2093820956
self.unknown_fields = unknown_fields
2093920957

@@ -26194,6 +26212,90 @@ def __init__(self, args=None, **unknown_fields):
2619426212

2619526213

2619626214

26215+
class UpdateUserSecretArg(Type):
26216+
_toSchema = {'auto_prune': 'auto-prune', 'content': 'content', 'description': 'description', 'expire_time': 'expire-time', 'label': 'label', 'params': 'params', 'rotate_policy': 'rotate-policy', 'upsertsecretarg': 'UpsertSecretArg', 'uri': 'uri'}
26217+
_toPy = {'UpsertSecretArg': 'upsertsecretarg', 'auto-prune': 'auto_prune', 'content': 'content', 'description': 'description', 'expire-time': 'expire_time', 'label': 'label', 'params': 'params', 'rotate-policy': 'rotate_policy', 'uri': 'uri'}
26218+
def __init__(self, upsertsecretarg=None, auto_prune=None, content=None, description=None, expire_time=None, label=None, params=None, rotate_policy=None, uri=None, **unknown_fields):
26219+
'''
26220+
upsertsecretarg : UpsertSecretArg
26221+
auto_prune : bool
26222+
content : SecretContentParams
26223+
description : str
26224+
expire_time : str
26225+
label : str
26226+
params : typing.Mapping[str, typing.Any]
26227+
rotate_policy : str
26228+
uri : str
26229+
'''
26230+
upsertsecretarg_ = UpsertSecretArg.from_json(upsertsecretarg) if upsertsecretarg else None
26231+
auto_prune_ = auto_prune
26232+
content_ = SecretContentParams.from_json(content) if content else None
26233+
description_ = description
26234+
expire_time_ = expire_time
26235+
label_ = label
26236+
params_ = params
26237+
rotate_policy_ = rotate_policy
26238+
uri_ = uri
26239+
26240+
# Validate arguments against known Juju API types.
26241+
if upsertsecretarg_ is not None and not isinstance(upsertsecretarg_, (dict, UpsertSecretArg)):
26242+
raise Exception("Expected upsertsecretarg_ to be a UpsertSecretArg, received: {}".format(type(upsertsecretarg_)))
26243+
26244+
if auto_prune_ is not None and not isinstance(auto_prune_, bool):
26245+
raise Exception("Expected auto_prune_ to be a bool, received: {}".format(type(auto_prune_)))
26246+
26247+
if content_ is not None and not isinstance(content_, (dict, SecretContentParams)):
26248+
raise Exception("Expected content_ to be a SecretContentParams, received: {}".format(type(content_)))
26249+
26250+
if description_ is not None and not isinstance(description_, (bytes, str)):
26251+
raise Exception("Expected description_ to be a str, received: {}".format(type(description_)))
26252+
26253+
if expire_time_ is not None and not isinstance(expire_time_, (bytes, str)):
26254+
raise Exception("Expected expire_time_ to be a str, received: {}".format(type(expire_time_)))
26255+
26256+
if label_ is not None and not isinstance(label_, (bytes, str)):
26257+
raise Exception("Expected label_ to be a str, received: {}".format(type(label_)))
26258+
26259+
if params_ is not None and not isinstance(params_, dict):
26260+
raise Exception("Expected params_ to be a Mapping, received: {}".format(type(params_)))
26261+
26262+
if rotate_policy_ is not None and not isinstance(rotate_policy_, (bytes, str)):
26263+
raise Exception("Expected rotate_policy_ to be a str, received: {}".format(type(rotate_policy_)))
26264+
26265+
if uri_ is not None and not isinstance(uri_, (bytes, str)):
26266+
raise Exception("Expected uri_ to be a str, received: {}".format(type(uri_)))
26267+
26268+
self.upsertsecretarg = upsertsecretarg_
26269+
self.auto_prune = auto_prune_
26270+
self.content = content_
26271+
self.description = description_
26272+
self.expire_time = expire_time_
26273+
self.label = label_
26274+
self.params = params_
26275+
self.rotate_policy = rotate_policy_
26276+
self.uri = uri_
26277+
self.unknown_fields = unknown_fields
26278+
26279+
26280+
26281+
class UpdateUserSecretArgs(Type):
26282+
_toSchema = {'args': 'args'}
26283+
_toPy = {'args': 'args'}
26284+
def __init__(self, args=None, **unknown_fields):
26285+
'''
26286+
args : typing.Sequence[~UpdateUserSecretArg]
26287+
'''
26288+
args_ = [UpdateUserSecretArg.from_json(o) for o in args or []]
26289+
26290+
# Validate arguments against known Juju API types.
26291+
if args_ is not None and not isinstance(args_, (bytes, str, list)):
26292+
raise Exception("Expected args_ to be a Sequence, received: {}".format(type(args_)))
26293+
26294+
self.args = args_
26295+
self.unknown_fields = unknown_fields
26296+
26297+
26298+
2619726299
class UpgradeModelParams(Type):
2619826300
_toSchema = {'agent_stream': 'agent-stream', 'dry_run': 'dry-run', 'ignore_agent_versions': 'ignore-agent-versions', 'model_tag': 'model-tag', 'target_version': 'target-version'}
2619926301
_toPy = {'agent-stream': 'agent_stream', 'dry-run': 'dry_run', 'ignore-agent-versions': 'ignore_agent_versions', 'model-tag': 'model_tag', 'target-version': 'target_version'}

juju/client/connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
'AllModelWatcher': {'versions': [2, 3, 4]},
3232
'AllWatcher': {'versions': [1, 2, 3, 4]},
3333
'Annotations': {'versions': [2]},
34-
'Application': {'versions': [14, 15, 16, 17]},
34+
'Application': {'versions': [14, 15, 16, 17, 19]},
3535
'ApplicationOffers': {'versions': [1, 2, 4]},
3636
'ApplicationScaler': {'versions': [1]},
3737
'Backups': {'versions': [1, 2, 3]},

0 commit comments

Comments
 (0)