Merge ~xavpaice/charm-nrpe:lp1937888 into charm-nrpe:master
- Git
- lp:~xavpaice/charm-nrpe
- lp1937888
- Merge into master
Status: | Merged |
---|---|
Approved by: | James Troup |
Approved revision: | 4344ba9b531ddeabd017b53ebaa468900679315c |
Merged at revision: | 74ca861645689f8eeeeebea7175d7c4b7a35f68d |
Proposed branch: | ~xavpaice/charm-nrpe:lp1937888 |
Merge into: | charm-nrpe:master |
Diff against target: |
269 lines (+115/-56) 4 files modified
hooks/nrpe_helpers.py (+29/-42) tests/functional/tests/bundles/focal.yaml (+1/-0) tests/functional/tests/tests.yaml (+3/-1) tests/unit/test_nrpe_helpers.py (+82/-13) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
🤖 prod-jenkaas-bootstack (community) | continuous-integration | Approve | |
James Troup (community) | Needs Fixing | ||
BootStack Reviewers | Pending | ||
Review via email: mp+408524@code.launchpad.net |
Commit message
Bind NRPE to local address
In cases where we specify to use public address and/or Juju returns a
public address regardless of the setting, we cannot use that address for
binding the NRPE service.
This change ensures get_local_
for binding the nrpe service, and if configured to do so returns the
public address for relation data and NRPE host exports.
Description of the change
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
A CI job is currently in progress. A follow up comment will be added when it completes.
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
FAILED: Continuous integration, rev:1332acc124e
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
James Troup (elmo) wrote : | # |
See comment inline.
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
A CI job is currently in progress. A follow up comment will be added when it completes.
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
FAILED: Continuous integration, rev:6dd95bb4bd2
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
A CI job is currently in progress. A follow up comment will be added when it completes.
Xav Paice (xavpaice) wrote : | # |
I've rewritten the change and added some tests.
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
FAILED: Continuous integration, rev:4f7b0a08823
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
FAILED: Continuous integration, rev:4f7b0a08823
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
A CI job is currently in progress. A follow up comment will be added when it completes.
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
FAILED: Continuous integration, rev:2edd09aa334
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
A CI job is currently in progress. A follow up comment will be added when it completes.
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
PASSED: Continuous integration, rev:a46e8c68dea
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
A CI job is currently in progress. A follow up comment will be added when it completes.
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote : | # |
PASSED: Continuous integration, rev:4344ba9b531
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Change successfully merged at revision 74ca861645689f8
Preview Diff
1 | diff --git a/hooks/nrpe_helpers.py b/hooks/nrpe_helpers.py |
2 | index 8384d76..b4f40b9 100644 |
3 | --- a/hooks/nrpe_helpers.py |
4 | +++ b/hooks/nrpe_helpers.py |
5 | @@ -77,42 +77,42 @@ class Monitors(dict): |
6 | return mons |
7 | |
8 | |
9 | -def get_local_ingress_address(binding): |
10 | +def get_ingress_address(binding, external=False): |
11 | """Get ingress IP address for a binding. |
12 | |
13 | - binding - e.g. 'monitors' |
14 | + Returns a local IP address for incoming requests to NRPE. |
15 | + |
16 | + :param binding: name of the binding, e.g. 'monitors' |
17 | + :param external: bool, if True return the public address if charm config requests |
18 | + otherwise return the local address which would be used for incoming |
19 | + nrpe requests. |
20 | """ |
21 | # using network-get to retrieve the address details if available. |
22 | hookenv.log("Getting ingress IP address for binding %s" % binding) |
23 | + if hookenv.config("nagios_address_type").lower() == "public" and external: |
24 | + return hookenv.unit_get("public-address") |
25 | + |
26 | + ip_address = None |
27 | try: |
28 | network_info = hookenv.network_get(binding) |
29 | if network_info is not None and "ingress-addresses" in network_info: |
30 | - hookenv.log("Using ingress-addresses") |
31 | - # workaround lp#1897261 |
32 | try: |
33 | ip_address = network_info["bind-addresses"][0]["addresses"][0][ |
34 | "address" |
35 | ] |
36 | + hookenv.log("Using ingress-addresses, found %s" % ip_address) |
37 | except KeyError: |
38 | - # ignore KeyError and populate ip_address per old method |
39 | - ip_address = None |
40 | - if ip_address not in network_info["ingress-addresses"]: |
41 | - ip_address = network_info["ingress-addresses"][0] |
42 | - hookenv.log(ip_address) |
43 | - return ip_address |
44 | - except (NotImplementedError, FileNotFoundError): |
45 | - # We'll fallthrough to the Pre 2.3 code below. |
46 | - pass |
47 | - |
48 | - # Pre 2.3 output |
49 | - try: |
50 | - ip_address = hookenv.network_get_primary_address(binding) |
51 | - hookenv.log("Using primary-addresses") |
52 | - except NotImplementedError: |
53 | - # pre Juju 2.0 |
54 | - ip_address = hookenv.unit_private_ip() |
55 | - hookenv.log("Using unit_private_ip") |
56 | - hookenv.log(ip_address) |
57 | + hookenv.log("Using primary-addresses") |
58 | + ip_address = hookenv.network_get_primary_address(binding) |
59 | + |
60 | + except (NotImplementedError, FileNotFoundError) as e: |
61 | + hookenv.log( |
62 | + "Unable to determine inbound IP address for binding {} with {}".format( |
63 | + binding, e |
64 | + ), |
65 | + level=hookenv.ERROR, |
66 | + ) |
67 | + |
68 | return ip_address |
69 | |
70 | |
71 | @@ -200,7 +200,8 @@ class MonitorsRelation(helpers.RelationContext): |
72 | |
73 | def provide_data(self): |
74 | """Return relation info.""" |
75 | - address = get_local_ingress_address("monitors") |
76 | + # get the address to send to Nagios for host definition |
77 | + address = get_ingress_address("monitors", external=True) |
78 | |
79 | relation_info = { |
80 | "target-id": self.principal_relation.nagios_hostname(), |
81 | @@ -299,24 +300,10 @@ class NagiosInfo(dict): |
82 | ) |
83 | self["nagios_hostname"] = self.principal_relation.nagios_hostname() |
84 | |
85 | - address = None |
86 | - if hookenv.config("nagios_address_type").lower() == "public": |
87 | - address = hookenv.unit_get("public-address") |
88 | - elif hookenv.config("nagios_master") != "None": |
89 | - # Try to work out the correct interface/IP. We can't use both |
90 | - # network-get nor 'unit-get private-address' because both can |
91 | - # return the wrong IP on systems with more than one interface |
92 | - # (LP: #1736050). |
93 | - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
94 | - s.connect((hookenv.config("nagios_master").split(",")[0], 80)) |
95 | - address = s.getsockname()[0] |
96 | - s.close() |
97 | - # Fallback to unit-get private-address |
98 | - if not address: |
99 | - address = hookenv.unit_get("private-address") |
100 | - |
101 | - self["nagios_ipaddress"] = address |
102 | - self["nrpe_ipaddress"] = get_local_ingress_address("monitors") |
103 | + # export_host.cfg.tmpl host definition for Nagios |
104 | + self["nagios_ipaddress"] = get_ingress_address("monitors", external=True) |
105 | + # Address configured for NRPE to listen on |
106 | + self["nrpe_ipaddress"] = get_ingress_address("monitors") |
107 | |
108 | self["dont_blame_nrpe"] = "1" if hookenv.config("dont_blame_nrpe") else "0" |
109 | self["debug"] = "1" if hookenv.config("debug") else "0" |
110 | diff --git a/tests/functional/tests/bundles/focal.yaml b/tests/functional/tests/bundles/focal.yaml |
111 | index 2689a08..33bea11 100644 |
112 | --- a/tests/functional/tests/bundles/focal.yaml |
113 | +++ b/tests/functional/tests/bundles/focal.yaml |
114 | @@ -3,6 +3,7 @@ applications: |
115 | rabbitmq-server: |
116 | charm: cs:rabbitmq-server |
117 | num_units: 1 |
118 | + constraints: root-disk=8G |
119 | container: |
120 | charm: cs:ubuntu |
121 | num_units: 1 |
122 | diff --git a/tests/functional/tests/tests.yaml b/tests/functional/tests/tests.yaml |
123 | index 8034f51..a661597 100644 |
124 | --- a/tests/functional/tests/tests.yaml |
125 | +++ b/tests/functional/tests/tests.yaml |
126 | @@ -1,7 +1,9 @@ |
127 | charm_name: nrpe |
128 | gate_bundles: |
129 | - - xenial |
130 | + - focal |
131 | - bionic |
132 | + - xenial |
133 | +smoke_bundles: |
134 | - focal |
135 | tests: |
136 | - tests.nrpe_tests.TestNrpe |
137 | diff --git a/tests/unit/test_nrpe_helpers.py b/tests/unit/test_nrpe_helpers.py |
138 | index fc17454..949eb92 100644 |
139 | --- a/tests/unit/test_nrpe_helpers.py |
140 | +++ b/tests/unit/test_nrpe_helpers.py |
141 | @@ -4,6 +4,7 @@ from unittest import mock |
142 | |
143 | import netifaces |
144 | |
145 | +import nrpe_helpers |
146 | from nrpe_helpers import match_cidr_to_ifaces |
147 | |
148 | |
149 | @@ -11,39 +12,107 @@ class TestMatchCidrToIfaces(unittest.TestCase): |
150 | """Test match_cidr_to_ifaces helper function.""" |
151 | |
152 | mock_iface_ip_data = { |
153 | - 'lo': '127.0.0.1', |
154 | - 'eno1': '10.0.0.0', |
155 | - 'eno2': '10.1.0.0', |
156 | - 'fan-252': '252.0.0.1', |
157 | + "lo": "127.0.0.1", |
158 | + "eno1": "10.0.0.0", |
159 | + "eno2": "10.1.0.0", |
160 | + "fan-252": "252.0.0.1", |
161 | } |
162 | |
163 | def test_single_dev_match(self): |
164 | """Test single interface match.""" |
165 | - self._run_mocked_test('10.0.0.0/16', ['eno1']) |
166 | + self._run_mocked_test("10.0.0.0/16", ["eno1"]) |
167 | |
168 | def test_multi_dev_match(self): |
169 | """Test multiple interface match.""" |
170 | - self._run_mocked_test('10.0.0.0/8', ['eno1', 'eno2']) |
171 | + self._run_mocked_test("10.0.0.0/8", ["eno1", "eno2"]) |
172 | |
173 | def test_no_dev_match(self): |
174 | """Test no interface match.""" |
175 | - self._run_mocked_test('192.168.0.0/16', []) |
176 | + self._run_mocked_test("192.168.0.0/16", []) |
177 | |
178 | def test_cidr_with_host_bits_set(self): |
179 | """Test invalid CIDR input (e.g. "eno1").""" |
180 | with self.assertRaises(Exception): |
181 | - match_cidr_to_ifaces('10.1.2.3/8') # Should be 10.0.0.0/8 |
182 | + match_cidr_to_ifaces("10.1.2.3/8") # Should be 10.0.0.0/8 |
183 | |
184 | def test_iface_passed_in_as_cidr(self): |
185 | """Test invalid CIDR input (e.g. "eno1").""" |
186 | with self.assertRaises(Exception): |
187 | - match_cidr_to_ifaces('eno1') |
188 | + match_cidr_to_ifaces("eno1") |
189 | |
190 | - @mock.patch('netifaces.ifaddresses') |
191 | - @mock.patch('netifaces.interfaces') |
192 | + @mock.patch("netifaces.ifaddresses") |
193 | + @mock.patch("netifaces.interfaces") |
194 | def _run_mocked_test(self, cidr, matches, ifaces_mock, addrs_mock): |
195 | iface_ip_tuples = list(self.mock_iface_ip_data.items()) |
196 | ifaces_mock.return_value = [t[0] for t in iface_ip_tuples] |
197 | - addrs_mock.side_effect = [{netifaces.AF_INET: [{'addr': t[1]}]} for t in |
198 | - iface_ip_tuples] |
199 | + addrs_mock.side_effect = [ |
200 | + {netifaces.AF_INET: [{"addr": t[1]}]} for t in iface_ip_tuples |
201 | + ] |
202 | self.assertEqual(match_cidr_to_ifaces(cidr), matches) |
203 | + |
204 | + |
205 | +class TestIngressAddress(unittest.TestCase): |
206 | + """Test functions to provide a suitable ingress address.""" |
207 | + |
208 | + @mock.patch("nrpe_helpers.hookenv.config") |
209 | + @mock.patch("nrpe_helpers.hookenv.network_get") |
210 | + def test_get_bind_address(self, mock_network_get, mock_config): |
211 | + """Prove we get a local IP address for interface binding.""" |
212 | + mock_config.return_value = "private" |
213 | + mock_network_get.return_value = { |
214 | + "bind-addresses": [ |
215 | + { |
216 | + "mac-address": "06:f1:3a:74:ad:fe", |
217 | + "interface-name": "ens5", |
218 | + "addresses": [ |
219 | + { |
220 | + "hostname": "", |
221 | + "address": "172.31.29.247", |
222 | + "cidr": "172.31.16.0/20", |
223 | + } |
224 | + ], |
225 | + "macaddress": "06:f1:3a:74:ad:fe", |
226 | + "interfacename": "ens5", |
227 | + } |
228 | + ], |
229 | + "egress-subnets": ["3.8.134.119/32"], |
230 | + "ingress-addresses": ["3.8.134.119"], |
231 | + } |
232 | + self.assertEqual(nrpe_helpers.get_ingress_address("mockbinding"), |
233 | + "172.31.29.247") |
234 | + |
235 | + @mock.patch("nrpe_helpers.hookenv.config") |
236 | + @mock.patch("nrpe_helpers.hookenv.network_get") |
237 | + def test_get_private_address(self, mock_network_get, mock_config): |
238 | + """Prove we get a local IP address for Nagios relation.""" |
239 | + mock_config.return_value = "private" |
240 | + mock_network_get.return_value = { |
241 | + "bind-addresses": [ |
242 | + { |
243 | + "mac-address": "06:f1:3a:74:ad:fe", |
244 | + "interface-name": "ens5", |
245 | + "addresses": [ |
246 | + { |
247 | + "hostname": "", |
248 | + "address": "172.31.29.247", |
249 | + "cidr": "172.31.16.0/20", |
250 | + } |
251 | + ], |
252 | + "macaddress": "06:f1:3a:74:ad:fe", |
253 | + "interfacename": "ens5", |
254 | + } |
255 | + ], |
256 | + "egress-subnets": ["3.8.134.119/32"], |
257 | + "ingress-addresses": ["3.8.134.119"], |
258 | + } |
259 | + self.assertEqual(nrpe_helpers.get_ingress_address("mockbinding", external=True), |
260 | + "172.31.29.247") |
261 | + |
262 | + @mock.patch("nrpe_helpers.hookenv.config") |
263 | + @mock.patch("nrpe_helpers.hookenv.unit_get") |
264 | + def test_get_public_address(self, mock_unit_get, mock_config): |
265 | + """Prove we get a public IP address for Nagios relation.""" |
266 | + mock_config.return_value = "public" |
267 | + mock_unit_get.return_value = "1.2.3.4" |
268 | + self.assertEqual(nrpe_helpers.get_ingress_address("mockbinding", external=True), |
269 | + "1.2.3.4") |
This merge proposal is being monitored by mergebot. Change the status to Approved to merge.