Merge ~sbparke/juju-lint/+git/juju-lint-1:bug/1915934-1 into juju-lint:master

Proposed by Steven Parker
Status: Merged
Approved by: James Troup
Approved revision: 76e9888a7bd35dd6b835a9e3a951fc3d0e0f16dc
Merged at revision: 003bbb91b8d7c48466faa98b833e66c97c7a333f
Proposed branch: ~sbparke/juju-lint/+git/juju-lint-1:bug/1915934-1
Merge into: juju-lint:master
Diff against target: 107 lines (+67/-3)
3 files modified
Makefile (+7/-0)
jujulint/lint.py (+23/-3)
tests/test_jujulint.py (+37/-0)
Reviewer Review Type Date Requested Status
Juju Lint maintainers Pending
Review via email: mp+411941@code.launchpad.net

Commit message

Added logic to parse multiple documents in exported bundle file for service overlays

Description of the change

Usage of saas service overlays and offers can lead to parsing errors as juju-lint is expecting a single yaml document within a juju export file.

This leads to BUG https://bugs.launchpad.net/juju-lint/+bug/1915934

applications:
  grafana:
    charm: cs:grafana-51
    channel: stable
    num_units: 1
    to:
    - 0
    options:
      install_method: snap
    bindings:
      "": oam-space
machines:
   0:
    constraints: tags=nagios spaces=oam-space
    series: bionic
--- # overlay.yaml <<-- starts new document
applications:
    grafana:
      offers:
       grafana:
         endpoints:
         - dashboards
         acl:
          admin: admin

leads to
yaml.composer.ComposerError: expected a single document in the stream
  in "<unicode string>", line 1, column 1:
    series: bionic
    ^
but found another document
  in "<unicode string>", line 627, column 1:
    --- # overlay.yaml
    ^

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 003bbb91b8d7c48466faa98b833e66c97c7a333f

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/Makefile b/Makefile
2index 917e96b..70a2762 100644
3--- a/Makefile
4+++ b/Makefile
5@@ -10,3 +10,10 @@ deb-src:
6
7 test:
8 tox -e unit
9+
10+build:
11+ snapcraft --use-lxd --debug
12+
13+clean:
14+ snapcraft clean --use-lxd
15+
16diff --git a/jujulint/lint.py b/jujulint/lint.py
17index 6c425bd..a59d66a 100755
18--- a/jujulint/lint.py
19+++ b/jujulint/lint.py
20@@ -969,16 +969,36 @@ class Linter:
21 if num_this_az < min_per_az:
22 self.model.az_unbalanced_apps[app_name] = [num_units, az_counter]
23
24- def lint_yaml_string(self, yaml):
25+ # Juju now creates multiple documents within a single export-bundle file
26+ # This is to support offer overlays
27+ # This occurs with the format string "--- # overlay.yaml"
28+ def get_main_bundle_doc(self, parsed_yaml_docs):
29+ """Get main bundle document from yaml input that may contain mutiple documents."""
30+ parsed_yaml = None
31+
32+ parsed_doc_list = list(parsed_yaml_docs)
33+ for doc in parsed_doc_list:
34+ offer_overlay = False
35+ applications = doc["applications"]
36+ for app in applications:
37+ if "offers" in doc["applications"][app]:
38+ offer_overlay = True
39+ if parsed_yaml is None or not offer_overlay:
40+ parsed_yaml = doc
41+ return(parsed_yaml)
42+
43+ def lint_yaml_string(self, yaml_string):
44 """Lint provided YAML string."""
45- parsed_yaml = yaml.safe_load(yaml)
46+ parsed_yaml_docs = yaml.safe_load_all(yaml_string)
47+ parsed_yaml = self.get_main_bundle_doc(parsed_yaml_docs)
48 return self.do_lint(parsed_yaml)
49
50 def lint_yaml_file(self, filename):
51 """Load and lint provided YAML file."""
52 if filename:
53 with open(filename, "r") as infile:
54- parsed_yaml = yaml.safe_load(infile.read())
55+ parsed_yaml_docs = yaml.safe_load_all(infile.read())
56+ parsed_yaml = self.get_main_bundle_doc(parsed_yaml_docs)
57 if parsed_yaml:
58 return self.do_lint(parsed_yaml)
59 self.logger.fubar("Failed to parse YAML from file {}".format(filename))
60diff --git a/tests/test_jujulint.py b/tests/test_jujulint.py
61index d865c63..e67f8af 100644
62--- a/tests/test_jujulint.py
63+++ b/tests/test_jujulint.py
64@@ -225,6 +225,43 @@ class TestLinter:
65 assert errors[0]["id"] == "ops-charm-missing"
66 assert errors[0]["charm"] == "telegraf"
67
68+ def test_overlay_documents(self, linter, tmp_path):
69+ """Test offer overlay format for saas cross model offers."""
70+ # juju now exports two documents to exported files.
71+ # We need to ignore the overlay document and still parse the main yaml doc
72+ yaml = """
73+applications:
74+ grafana:
75+ charm: cs:grafana-51
76+ channel: stable
77+ num_units: 1
78+ to:
79+ - 0
80+ options:
81+ install_method: snap
82+ bindings:
83+ "": oam-space
84+machines:
85+ 0:
86+ constraints: tags=nagios spaces=oam-space
87+ series: bionic
88+--- # overlay.yaml
89+applications:
90+ grafana:
91+ offers:
92+ grafana:
93+ endpoints:
94+ - dashboards
95+ acl:
96+ admin: admin"""
97+
98+ linter.lint_yaml_string(yaml)
99+
100+ yaml_path = tmp_path / "bundle.yaml"
101+ yaml_path.write_text(yaml)
102+
103+ linter.lint_yaml_file(yaml_path)
104+
105 def test_unrecognised_charm(self, linter, juju_status):
106 """Test that unrecognised charms are detected."""
107 # drop 'ubuntu' from the known charms

Subscribers

People subscribed via source and target branches