Skip to content

Commit 67128e9

Browse files
committed
Upload pending local resources after server side deploy
Splits out the second part of the add_local_resources into a separate _upload function to use after DeployFromRepository reports the pending file uploads if there's any
1 parent 48570bb commit 67128e9

1 file changed

Lines changed: 49 additions & 27 deletions

File tree

juju/model.py

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,6 +1743,8 @@ async def deploy(
17431743
if base:
17441744
charm_origin.base = utils.parse_base_arg(base)
17451745

1746+
server_side_deploy = False
1747+
17461748
if res.is_bundle:
17471749
handler = BundleHandler(self, trusted=trust, forced=force)
17481750
await handler.fetch_plan(url, charm_origin, overlays=overlays)
@@ -1774,9 +1776,20 @@ async def deploy(
17741776
else:
17751777
charm_origin = add_charm_res.charm_origin
17761778
if Schema.CHARM_HUB.matches(url.schema):
1777-
resources = await self._add_charmhub_resources(res.app_name,
1778-
identifier,
1779-
add_charm_res.charm_origin)
1779+
1780+
if client.ApplicationFacade.best_facade_version(self.connection()) >= 19:
1781+
server_side_deploy = True
1782+
else:
1783+
# TODO (cderici): this is an awkward workaround for basically not calling
1784+
# the AddPendingResources in case this is a server side deploy.
1785+
# If that's the case, then the store resources (and revisioned local
1786+
# resources) are handled at the server side if this is a server side deploy
1787+
# (local uploads are handled right after we get the pendingIDs returned
1788+
# from the facade call).
1789+
resources = await self._add_charmhub_resources(res.app_name,
1790+
identifier,
1791+
add_charm_res.charm_origin)
1792+
17801793
is_sub = await self.charmhub.is_subordinate(url.name)
17811794
if is_sub:
17821795
if num_units > 1:
@@ -1829,6 +1842,7 @@ async def deploy(
18291842
charm_origin=charm_origin,
18301843
attach_storage=attach_storage,
18311844
force=force,
1845+
server_side_deploy=server_side_deploy,
18321846
)
18331847

18341848
async def _add_charm(self, charm_url, origin):
@@ -2029,42 +2043,42 @@ async def add_local_resources(self, application, entity_url, metadata, resources
20292043
'username': '',
20302044
'password': '',
20312045
}
2032-
20332046
data = yaml.dump(docker_image_details)
2047+
else:
2048+
p = Path(path)
2049+
data = p.read_text() if p.exists() else ''
20342050

2035-
hash_alg = hashlib.sha3_384
2036-
2037-
charmresource['fingerprint'] = hash_alg(bytes(data, 'utf-8')).digest()
2051+
self._upload(data, path, application, name, resource_type, pending_id)
20382052

2039-
conn, headers, path_prefix = self.connection().https_connection()
2053+
return resource_map
20402054

2041-
query = "?pendingid={}".format(pending_id)
2042-
url = "{}/applications/{}/resources/{}{}".format(
2043-
path_prefix, application, name, query)
2044-
if resource_type == "oci-image":
2045-
disp = "multipart/form-data; filename=\"{}\"".format(path)
2046-
else:
2047-
disp = "form-data; filename=\"{}\"".format(path)
2055+
def _upload(self, data, path, app_name, res_name, res_type, pending_id):
2056+
conn, headers, path_prefix = self.connection().https_connection()
20482057

2049-
headers['Content-Type'] = 'application/octet-stream'
2050-
headers['Content-Length'] = len(data)
2051-
headers['Content-Sha384'] = charmresource['fingerprint'].hex()
2052-
headers['Content-Disposition'] = disp
2058+
query = "?pendingid={}".format(pending_id)
2059+
url = "{}/applications/{}/resources/{}{}".format(path_prefix, app_name, res_name, query)
2060+
if res_type == "oci-image":
2061+
disp = "multipart/form-data; filename=\"{}\"".format(path)
2062+
else:
2063+
disp = "form-data; filename=\"{}\"".format(path)
20532064

2054-
conn.request('PUT', url, data, headers)
2065+
headers['Content-Type'] = 'application/octet-stream'
2066+
headers['Content-Length'] = len(data)
2067+
headers['Content-Sha384'] = hashlib.sha384(bytes(data, 'utf-8')).hexdigest()
2068+
headers['Content-Disposition'] = disp
20552069

2056-
response = conn.getresponse()
2057-
result = response.read().decode()
2058-
if not response.status == 200:
2059-
raise JujuError(result)
2070+
conn.request('PUT', url, data, headers)
20602071

2061-
return resource_map
2072+
response = conn.getresponse()
2073+
result = response.read().decode()
2074+
if not response.status == 200:
2075+
raise JujuError(result)
20622076

20632077
async def _deploy(self, charm_url, application, series, config,
20642078
constraints, endpoint_bindings, resources, storage,
20652079
channel=None, num_units=None, placement=None,
20662080
devices=None, charm_origin=None, attach_storage=[],
2067-
force=False):
2081+
force=False, server_side_deploy=False):
20682082
"""Logic shared between `Model.deploy` and `BundleHandler.deploy`.
20692083
"""
20702084
log.info('Deploying %s', charm_url)
@@ -2077,7 +2091,7 @@ async def _deploy(self, charm_url, application, series, config,
20772091

20782092
app_facade = client.ApplicationFacade.from_connection(self.connection())
20792093

2080-
if client.ApplicationFacade.best_facade_version(self.connection()) >= 19:
2094+
if server_side_deploy:
20812095
# Call DeployFromRepository
20822096
app = client.DeployFromRepositoryArg(
20832097
applicationname=application,
@@ -2125,6 +2139,14 @@ async def _deploy(self, charm_url, application, series, config,
21252139
errors = [r.error.message for r in result.results if r.error]
21262140
if errors:
21272141
raise JujuError('\n'.join(errors))
2142+
2143+
for _result in result.results:
2144+
for pending_upload_resource in _result.pendingresourceuploads:
2145+
_path = pending_upload_resource.filename
2146+
p = Path(_path)
2147+
data = p.read_text() if p.exists() else ''
2148+
self._upload(data, _path, application, pending_upload_resource.name, 'file', '')
2149+
21282150
return await self._wait_for_new('application', application)
21292151

21302152
async def destroy_unit(self, unit_id, destroy_storage=False, dry_run=False, force=False, max_wait=None):

0 commit comments

Comments
 (0)