Skip to content

Commit bde724b

Browse files
authored
Merge pull request #481 from SimonRichardson/merge-master-2.9
#481 Merge 2.9 into master This is brings in 2.9-rc3 schema as well, so that we're dealing with the latest changes. Conflicts: _client3.py - just re-ran the `make client` as the code is autogenerated. 5e23162 (upstream/master) Merge pull request #480 from SimonRichardson/release-2.8.6 3e23b74 (origin/master, origin/HEAD, master) Merge pull request #479 from SimonRichardson/schema-update-2.8.10 7f96863 Merge pull request #478 from SimonRichardson/scale-typo fd1438c Merge pull request #475 from achilleasa/provide-accessor-for-machine-hostname-field 1015f4d Expand wait_for_idle to support waiting for status (#473) 7829fd0 Merge pull request #471 from SimonRichardson/release-2.8.5 fd36c8f Merge pull request #470 from juju/johnsca/bundle-charm-files-and-wait 3d91d6b Merge pull request #469 from juju/johnsca/accept-charm-files 4e4e108 Merge pull request #465 from juju/johnsca/update-websockets/py39 d696937 Merge pull request #467 from gnuoy/issue/466
2 parents fa1b85f + d6ea321 commit bde724b

37 files changed

Lines changed: 95627 additions & 1692 deletions

.github/workflows/tox.yaml

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,36 @@ name: Unit Tests
33
on: [push, pull_request]
44

55
jobs:
6+
lint:
7+
name: Lint
8+
runs-on: ubuntu-latest
9+
strategy:
10+
matrix:
11+
python: [3.5, 3.6, 3.7, 3.8, 3.9]
12+
steps:
13+
- name: Check out code
14+
uses: actions/checkout@v2
15+
- name: Setup Python
16+
uses: actions/setup-python@v2
17+
with:
18+
python-version: ${{ matrix.python }}
19+
- name: Install dependencies
20+
run: |
21+
pip install tox
22+
- name: Run lint
23+
run: tox -e lint
624
unit-tests:
725
runs-on: ubuntu-latest
26+
strategy:
27+
matrix:
28+
python: [3.5, 3.6, 3.7, 3.8, 3.9]
829
steps:
930
- uses: actions/checkout@v2
1031
- name: Setup Python
1132
uses: actions/setup-python@v1
1233
with:
13-
python-version: 3.8
14-
- name: Install Tox and any other packages
34+
python-version: ${{ matrix.python }}
35+
- name: Install dependencies
1536
run: pip install tox
16-
- name: Run Lint and Unit Tests
17-
run: tox -e lint,py3
37+
- name: Run unit tests
38+
run: tox -e py3

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.8.4
1+
2.8.6

docs/changelog.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
Changelog
22
---------
33

4+
2.8.6
5+
^^^^^
6+
7+
Tuesday March 23 2021
8+
9+
* Update facade methods for Juju 2.8.10
10+
* Bug fix - Fix typo in param name for ScaleApplications
11+
* Introduction of hostname property for Machines
12+
13+
2.8.5
14+
^^^^^
15+
16+
Monday February 8 2021
17+
18+
* Implement add_space and get_spaces.
19+
* Update facade controllers.
20+
* Support already archived (.charm or .zip) local charms.
21+
* Introduction of wait_for_bundle method.
22+
* Bug fix - Handle None in list_offers results
23+
* Bug fix - Update libraries to support Python 3.9+
24+
425
2.8.4
526
^^^^^
627

examples/machine_hostname.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env python3.5
2+
3+
"""
4+
This example:
5+
6+
1. Connects to the current model
7+
2. Creates a machine
8+
3. Waits for the machine agent to start and prints out the reported machine
9+
hostname.
10+
11+
NOTE: this example requires a 2.8.10+ controller.
12+
"""
13+
import logging
14+
15+
from juju import loop
16+
from juju.model import Model
17+
18+
MB = 1
19+
GB = 1024
20+
21+
22+
async def main():
23+
model = Model()
24+
await model.connect()
25+
26+
try:
27+
# Add a machine and wait until the machine agents starts
28+
machine1 = await model.add_machine()
29+
await model.block_until(
30+
lambda: machine1.agent_status == 'started')
31+
32+
# At this point we can access the reported hostname via the hostname
33+
# property of the machine model.
34+
print("machine1 hostname: {}".format(machine1.hostname))
35+
36+
await machine1.destroy(force=True)
37+
finally:
38+
await model.disconnect()
39+
40+
41+
if __name__ == '__main__':
42+
logging.basicConfig(level=logging.DEBUG)
43+
ws_logger = logging.getLogger('websockets.protocol')
44+
ws_logger.setLevel(logging.INFO)
45+
46+
loop.run(main())

juju/application.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,9 @@ async def scale(self, scale=None, scale_change=None):
168168
self.name, 'to' if scale else 'by', scale or scale_change)
169169

170170
await app_facade.ScaleApplications(applications=[
171-
client.ScaleApplicationParam(application_tag=self.tag,
172-
scale=scale,
173-
scale_change=scale_change)
171+
client.ScaleApplicationParams(application_tag=self.tag,
172+
scale=scale,
173+
scale_change=scale_change)
174174
])
175175

176176
def allocate(self, budget, value):

juju/bundle.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import asyncio
22
import logging
33
import os
4+
import zipfile
45
from pathlib import Path
56

67
import yaml
@@ -72,7 +73,7 @@ async def _validate_bundle(self, bundle):
7273
)
7374
return bundle
7475

75-
async def _handle_local_charms(self, bundle):
76+
async def _handle_local_charms(self, bundle, bundle_dir):
7677
"""Search for references to local charms (i.e. filesystem paths)
7778
in the bundle. Upload the local charms to the model, and replace
7879
the filesystem paths with appropriate 'local:' paths in the bundle.
@@ -89,9 +90,16 @@ async def _handle_local_charms(self, bundle):
8990
apps_dict = bundle.get('applications', bundle.get('services', {}))
9091
for app_name in self.applications:
9192
app_dict = apps_dict[app_name]
92-
charm_dir = os.path.abspath(os.path.expanduser(app_dict['charm']))
93-
if not os.path.isdir(charm_dir):
94-
continue
93+
charm_dir = app_dict['charm']
94+
try:
95+
charm_path = (bundle_dir / charm_dir).resolve()
96+
if not (charm_path.is_dir() or
97+
(charm_path.is_file() and
98+
charm_path.suffix in ('.charm', '.zip'))):
99+
continue
100+
charm_dir = str(charm_path)
101+
except ValueError:
102+
pass
95103
series = (
96104
app_dict.get('series') or
97105
default_series or
@@ -122,18 +130,24 @@ async def _handle_local_charms(self, bundle):
122130

123131
async def fetch_plan(self, entity_id):
124132
is_store_url = entity_id.startswith('cs:')
133+
is_local = False
134+
bundle_dir = None
125135

126136
if not is_store_url and os.path.isfile(entity_id):
127137
bundle_yaml = Path(entity_id).read_text()
138+
is_local = True
139+
bundle_dir = Path(entity_id).parent
128140
elif not is_store_url and os.path.isdir(entity_id):
129141
bundle_yaml = (Path(entity_id) / "bundle.yaml").read_text()
142+
bundle_dir = Path(entity_id)
130143
else:
131144
bundle_yaml = await self.charmstore.files(entity_id,
132145
filename='bundle.yaml',
133146
read_file=True)
134147
self.bundle = yaml.safe_load(bundle_yaml)
135148
self.bundle = await self._validate_bundle(self.bundle)
136-
self.bundle = await self._handle_local_charms(self.bundle)
149+
if is_local:
150+
self.bundle = await self._handle_local_charms(self.bundle, bundle_dir)
137151

138152
self.plan = await self.bundle_facade.GetChanges(
139153
bundleurl=entity_id,
@@ -179,11 +193,16 @@ def get_charm_series(path):
179193
180194
Returns None if no series can be determined.
181195
"""
182-
md = Path(path) / "metadata.yaml"
183-
if not md.exists():
184-
return None
185196
try:
186-
data = yaml.safe_load(md.open())
197+
if path.endswith('.charm'):
198+
md = "metadata.yaml in %s" % path
199+
with zipfile.ZipFile(path, 'r') as charm_file:
200+
data = yaml.safe_load(charm_file.read('metadata.yaml'))
201+
else:
202+
md = Path(path) / "metadata.yaml"
203+
if not md.exists():
204+
return None
205+
data = yaml.safe_load(md.open())
187206
except yaml.YAMLError as exc:
188207
if hasattr(exc, "problem_mark"):
189208
mark = exc.problem_mark

0 commit comments

Comments
 (0)