Skip to content

Commit

Permalink
Merge pull request #601 from cderici/attach-resources
Browse files Browse the repository at this point in the history
#601

#### Description

This adds `attach-resource` functionality to pylibjuju.

Fixes #294

#### QA Steps

```sh
tox -e integration -- tests/integration/test_model.py::test_attach_resource
```

#### Notes & Discussion
  • Loading branch information
jujubot authored Dec 13, 2021
2 parents dd382ec + 7b94bac commit 9b9ef49
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 0 deletions.
35 changes: 35 additions & 0 deletions juju/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import hashlib
import json
import logging
import pathlib
Expand Down Expand Up @@ -433,6 +434,40 @@ async def get_actions(self, schema=False):
actions = {k: v.description for k, v in actions.items()}
return actions

def attach_resource(self, resource_name, file_name, file_obj):
"""Updates the resource for an application by uploading file from
local disk to the Juju controller.
:param str resource_name: Name of the resource to be updated.
:param str file_name: Name of the local file to be uploaded.
:param TextIOWrapper file_obj: Actual object to be read for data.
"""
conn, headers, path_prefix = self.connection.https_connection()

url = "{}/applications/{}/resources/{}".format(
path_prefix, self.name, resource_name)

data = file_obj.read()

headers['Content-Type'] = 'application/octet-stream'
headers['Content-Length'] = len(data)
headers['Content-Sha384'] = hashlib.sha384(bytes(data, 'utf-8')).hexdigest()

file_name = str(file_name)
if not file_name.startswith('./'):
file_name = './' + file_name

headers['Content-Disposition'] = "form-data; filename=\"{}\"".format(file_name)
headers['Accept-Encoding'] = 'gzip'
headers['Bakery-Protocol-Version'] = 3
headers['Connection'] = 'close'

conn.request('PUT', url, data, headers)
response = conn.getresponse()
result = response.read().decode()
if not response.status == 200:
raise JujuError(result)

async def get_resources(self):
"""Return resources for this application.
Expand Down
1 change: 1 addition & 0 deletions tests/integration/file-resource-charm/test.file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo
16 changes: 16 additions & 0 deletions tests/integration/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,22 @@ async def test_local_file_resource_charm(event_loop):
assert ress['file-res']


@base.bootstrapped
@pytest.mark.asyncio
async def test_attach_resource(event_loop):
charm_path = TESTS_DIR / 'integration' / 'file-resource-charm'
async with base.CleanModel() as model:
resources = {"file-res": "test.file"}
app = await model.deploy(str(charm_path), resources=resources)
assert 'file-resource-charm' in model.applications

await model.wait_for_idle()
assert app.units[0].agent_status == 'idle'

with open(str(charm_path / 'test.file')) as f:
app.attach_resource('file-res', 'test.file', f)


@base.bootstrapped
@pytest.mark.asyncio
async def test_store_resources_bundle(event_loop):
Expand Down

0 comments on commit 9b9ef49

Please sign in to comment.