Merge ~jfguedez/juju-lint:bug/1944406 into juju-lint:master

Proposed by Jose Guedez
Status: Superseded
Proposed branch: ~jfguedez/juju-lint:bug/1944406
Merge into: juju-lint:master
Prerequisite: ~jfguedez/juju-lint:bug/1855858
Diff against target: 190 lines (+102/-15)
3 files modified
contrib/includes/base.yaml (+2/-0)
jujulint/lint.py (+32/-15)
tests/test_jujulint.py (+68/-0)
Reviewer Review Type Date Requested Status
Juju Lint maintainers Pending
Review via email: mp+408921@code.launchpad.net

This proposal has been superseded by a proposal from 2021-09-23.

Commit message

Add a "suffix" option for config checks

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
James Troup (elmo) wrote :

So here's the problem: we're trying to get rid of nrpe-container/nrpe-{host,physical}. Can I suggest instead a change to the nrpe charm which disables these checks if run in a container? See also:

  https://code.launchpad.net/~vultaire/charm-nrpe/+git/charm-nrpe/+merge/407276

Revision history for this message
Jose Guedez (jfguedez) wrote :

Hi James,

I updated the code to be able to handle both situations (to account for a transition period for existing setups). Also added several test cases to cover the success/failure cases for the case with and without suffixes.

Please take another look when you have a chance. Thanks.

Unmerged commits

b8b70ad... by Jose Guedez

Add a "suffix" option for config checks

The base charm name is always checked if present.

Closes-Bug: 1944406

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/contrib/includes/base.yaml b/contrib/includes/base.yaml
2index bc39a46..d8063eb 100644
3--- a/contrib/includes/base.yaml
4+++ b/contrib/includes/base.yaml
5@@ -8,8 +8,10 @@ config:
6 nrpe:
7 lacp_bonds:
8 neq: ""
9+ suffixes: [host, physical]
10 netlinks:
11 neq: ""
12+ suffixes: [host, physical]
13 landscape-client:
14 disable-unattended-upgrades:
15 eq: true
16diff --git a/jujulint/lint.py b/jujulint/lint.py
17index 58ce1f1..6c425bd 100755
18--- a/jujulint/lint.py
19+++ b/jujulint/lint.py
20@@ -161,7 +161,9 @@ class Linter:
21 for sub in subordinates:
22 if sub in self.model.subs_on_machines[machine]:
23 charm = self.model.app_to_charm[sub]
24- allow_multiple = self.lint_rules['subordinates'][charm].get("allow-multiple")
25+ allow_multiple = self.lint_rules["subordinates"][charm].get(
26+ "allow-multiple"
27+ )
28 if not allow_multiple:
29 self.model.duelling_subs.setdefault(sub, set())
30 self.model.duelling_subs[sub].add(machine)
31@@ -341,20 +343,42 @@ class Linter:
32 )
33 return False
34
35- def check_config(self, name, config, rules):
36+ def check_config(self, app_name, config, rules):
37 """Check application against provided rules."""
38 rules = dict(rules)
39 for rule in rules:
40- self._log_with_header("Checking {} for configuration {}".format(name, rule))
41+ self._log_with_header(
42+ "Checking {} for configuration {}".format(app_name, rule)
43+ )
44+
45+ # Handle app suffix for config checks. If the suffix is provided
46+ # and it does not match, then we skip the check. LP#1944406
47+ # The base charm name is always checked if present.
48+ suffixes = rules[rule].pop("suffixes", [])
49+ if suffixes:
50+ charm_name = self.model.app_to_charm[app_name]
51+ target_app_names = [
52+ "{}-{}".format(charm_name, suffix) for suffix in suffixes
53+ ]
54+ target_app_names.append(charm_name)
55+
56+ if app_name not in target_app_names:
57+ self._log_with_header(
58+ "The app name didn't match any name target for this charm: '{}' (skipping check)".format(
59+ app_name
60+ )
61+ )
62+ continue
63+
64 for check_op, check_value in rules[rule].items():
65 # check_op should be the operator name, e.g. (eq, neq, gte, isset)
66 if check_op in VALID_CONFIG_CHECKS:
67 check_method = getattr(self, check_op)
68- check_method(name, check_value, rule, config)
69+ check_method(app_name, check_value, rule, config)
70 else:
71 self._log_with_header(
72 "Application {} has unknown check operation for {}: {}.".format(
73- name,
74+ app_name,
75 rule,
76 check_op,
77 ),
78@@ -429,9 +453,7 @@ class Linter:
79 self._log_with_header("... matched, not wanted on this host")
80 continue
81 elif where == "host only":
82- self._log_with_header(
83- "requirement is 'host only' form...."
84- )
85+ self._log_with_header("requirement is 'host only' form....")
86 if utils.is_container(machine):
87 self._log_with_header("... and we are a container, checking")
88 # XXX check alternate names?
89@@ -442,9 +464,7 @@ class Linter:
90 continue
91 self._log_with_header("... and we are a host, will fallthrough")
92 elif where == "metal only":
93- self._log_with_header(
94- "requirement is 'metal only' form...."
95- )
96+ self._log_with_header("requirement is 'metal only' form....")
97 if not utils.is_metal(machine, machines_data.get(machine, {})):
98 self._log_with_header("... and we are not a metal, checking")
99 if required_sub in present_subs:
100@@ -483,10 +503,7 @@ class Linter:
101 looking_for = "{}-{}".format(required_sub, suffix)
102 self._log_with_header("-> Looking for {}".format(looking_for))
103 if looking_for in present_subs:
104- self.logger.debug("-> FOUND!!!")
105- self.cloud_name,
106- self.controller_name,
107- self.model_name,
108+ self._log_with_header("-> FOUND!!!")
109 found = True
110 if not found:
111 for sub in present_subs:
112diff --git a/tests/test_jujulint.py b/tests/test_jujulint.py
113index c74c550..d865c63 100644
114--- a/tests/test_jujulint.py
115+++ b/tests/test_jujulint.py
116@@ -433,6 +433,74 @@ class TestLinter:
117 assert errors[0]["expected_value"] is False
118 assert errors[0]["actual_value"] is True
119
120+ def test_config_eq_suffix_match(self, linter, juju_status):
121+ """Test the config condition 'eq'. when suffix matches."""
122+ linter.lint_rules["config"] = {
123+ "ubuntu": {"fake-opt": {"eq": False, "suffixes": ["host", "physical"]}}
124+ }
125+ juju_status["applications"]["ubuntu"]["options"] = {"fake-opt": True}
126+ juju_status["applications"]["ubuntu-host"] = juju_status["applications"].pop(
127+ "ubuntu"
128+ )
129+ linter.do_lint(juju_status)
130+
131+ errors = linter.output_collector["errors"]
132+ assert len(errors) == 1
133+ assert errors[0]["id"] == "config-eq-check"
134+ assert errors[0]["application"] == "ubuntu-host"
135+ assert errors[0]["rule"] == "fake-opt"
136+ assert errors[0]["expected_value"] is False
137+ assert errors[0]["actual_value"] is True
138+
139+ def test_config_eq_suffix_match_charm_name(self, linter, juju_status):
140+ """Test the config condition 'eq'. when suffix and base charm name."""
141+ linter.lint_rules["config"] = {
142+ "ubuntu": {"fake-opt": {"eq": False, "suffixes": ["host", "physical"]}}
143+ }
144+ juju_status["applications"]["ubuntu"]["options"] = {"fake-opt": True}
145+ linter.do_lint(juju_status)
146+
147+ errors = linter.output_collector["errors"]
148+ assert len(errors) == 1
149+ assert errors[0]["id"] == "config-eq-check"
150+ assert errors[0]["application"] == "ubuntu"
151+ assert errors[0]["rule"] == "fake-opt"
152+ assert errors[0]["expected_value"] is False
153+ assert errors[0]["actual_value"] is True
154+
155+ def test_config_eq_suffix_skip(self, linter, juju_status):
156+ """Test the config condition 'eq'. when suffix doesn't match."""
157+ linter.lint_rules["config"] = {
158+ "ubuntu": {"fake-opt": {"eq": False, "suffixes": ["host", "physical"]}}
159+ }
160+ juju_status["applications"]["ubuntu"]["options"] = {"fake-opt": True}
161+ juju_status["applications"]["ubuntu-container"] = juju_status[
162+ "applications"
163+ ].pop("ubuntu")
164+ linter.do_lint(juju_status)
165+
166+ errors = linter.output_collector["errors"]
167+ assert not errors
168+
169+ def test_config_eq_no_suffix_check_all(self, linter, juju_status):
170+ """Test the config condition 'eq'. when no suffix all should be checked."""
171+ linter.lint_rules["config"] = {
172+ "ubuntu": {"fake-opt": {"eq": False}}
173+ }
174+ juju_status["applications"]["ubuntu"]["options"] = {"fake-opt": True}
175+ juju_status["applications"]["ubuntu-host"] = juju_status["applications"].pop(
176+ "ubuntu"
177+ )
178+ linter.do_lint(juju_status)
179+
180+ errors = linter.output_collector["errors"]
181+ assert len(errors) == 1
182+ assert errors[0]["id"] == "config-eq-check"
183+ assert errors[0]["application"] == "ubuntu-host"
184+ assert errors[0]["rule"] == "fake-opt"
185+ assert errors[0]["expected_value"] is False
186+ assert errors[0]["actual_value"] is True
187+
188 def test_config_neq_valid(self, linter, juju_status):
189 """Test the config condition 'neq'."""
190 linter.lint_rules["config"] = {"ubuntu": {"fake-opt": {"neq": "foo"}}}

Subscribers

People subscribed via source and target branches