Merge ~barryprice/charm-telegraf:split_prometheus_client_config into charm-telegraf:master
- Git
- lp:~barryprice/charm-telegraf
- split_prometheus_client_config
- Merge into master
Proposed by
Barry Price
Status: | Merged |
---|---|
Approved by: | Barry Price |
Approved revision: | 6296374c10538503897d0bebd576742e5fe414e2 |
Merged at revision: | 681fc188e8d79ae8420393be2b00d62d76099f7b |
Proposed branch: | ~barryprice/charm-telegraf:split_prometheus_client_config |
Merge into: | charm-telegraf:master |
Diff against target: |
382 lines (+132/-73) 4 files modified
src/reactive/telegraf.py (+107/-45) src/templates/prometheus_client.tmpl (+3/-0) src/templates/telegraf.conf.tmpl (+0/-6) src/tests/unit/test_telegraf.py (+22/-22) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Haw Loeung | +1 | Approve | |
Canonical IS Reviewers | Pending | ||
BootStack Reviewers | Pending | ||
Review via email: mp+398218@code.launchpad.net |
This proposal supersedes a proposal from 2021-01-27.
Commit message
Split prometheus_client output config out of the main config file. Allow a prometheus-client relation to prometheus even if prometheus_
Description of the change
To post a comment you must log in.
Revision history for this message
Laurent Sesquès (sajoupa) wrote : Posted in a previous version of this proposal | # |
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : Posted in a previous version of this proposal | # |
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 : Posted in a previous version of this proposal | # |
Unable to determine commit message from repository - please click "Set commit message" and enter the commit message manually.
Revision history for this message
Haw Loeung (hloeung) : Posted in a previous version of this proposal | # |
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 681fc188e8d79ae
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/reactive/telegraf.py b/src/reactive/telegraf.py |
2 | index d8fd268..82cf10e 100644 |
3 | --- a/src/reactive/telegraf.py |
4 | +++ b/src/reactive/telegraf.py |
5 | @@ -183,7 +183,14 @@ def list_config_files(): |
6 | current_states = get_states() |
7 | |
8 | for plugin in list_supported_plugins(): |
9 | - if "plugins.{}.configured".format(plugin) in current_states.keys(): |
10 | + # The prometheus_client plugin can be configured either from a relation or |
11 | + # from the juju config |
12 | + if ("plugins.{}.configured".format(plugin) in current_states.keys()) or ( |
13 | + "{}.configured".format(plugin) in current_states.keys() |
14 | + ): |
15 | + # The "prometheus-client" relation sets the "prometheus_client" plugin |
16 | + if plugin == "prometheus-client": |
17 | + plugin = "prometheus_client" |
18 | config_path = "{}/{}.conf".format(get_configs_dir(), plugin) |
19 | config_files.append(config_path) |
20 | |
21 | @@ -527,9 +534,6 @@ def configure_telegraf(): # noqa: C901 |
22 | ) |
23 | context["logfile"] = "" |
24 | |
25 | - if get_prometheus_port(): |
26 | - context["prometheus_output_port"] = get_prometheus_port() |
27 | - check_prometheus_port("prometheus_output", get_prometheus_port()) |
28 | context["extra_options"] = get_extra_options() |
29 | |
30 | if get_socket_listener_port(): |
31 | @@ -645,6 +649,7 @@ def install_telegraf(): |
32 | |
33 | @when("telegraf.installed") |
34 | @when("apt.installed.telegraf") |
35 | +@when("plugins.prometheus-client.configured") |
36 | @when_not("telegraf.configured") |
37 | @when_not("telegraf.apt.configured") |
38 | def configure_telegraf_deb(): |
39 | @@ -653,6 +658,7 @@ def configure_telegraf_deb(): |
40 | |
41 | @when("telegraf.installed") |
42 | @when("snap.installed.telegraf") |
43 | +@when("plugins.prometheus-client.configured") |
44 | @when_not("telegraf.configured") |
45 | @when_not("telegraf.snap.configured") |
46 | def configure_telegraf_snap(): |
47 | @@ -677,6 +683,7 @@ def handle_config_changes(): |
48 | if config.changed("extra_options"): |
49 | for plugin in list_supported_plugins(): |
50 | clear_flag("plugins.{}.configured".format(plugin)) |
51 | + clear_flag("prometheus-client.relation.configured") |
52 | # if something else changed, let's reconfigure telegraf itself just in case |
53 | |
54 | if config.changed("extra_plugins"): |
55 | @@ -689,6 +696,12 @@ def handle_config_changes(): |
56 | ): |
57 | clear_flag("telegraf.installed") |
58 | clear_flag("extra_plugins.configured") |
59 | + clear_flag("plugins.prometheus-client.configured") |
60 | + clear_flag("prometheus-client.relation.configured") |
61 | + |
62 | + if config.changed("prometheus_output_port"): |
63 | + clear_flag("plugins.prometheus-client.configured") |
64 | + clear_flag("prometheus-client.relation.configured") |
65 | clear_flag("telegraf.configured") |
66 | clear_flag("telegraf.apt.configured") |
67 | clear_flag("telegraf.snap.configured") |
68 | @@ -1207,59 +1220,108 @@ def influxdb_api_output(influxdb): |
69 | set_flag("telegraf.needs_reload") |
70 | |
71 | |
72 | +def generate_prometheus_output_config(prometheus_output_port): |
73 | + # If extra_options are set for prometheus_client, let's integrate them |
74 | + extra_options = get_extra_options() |
75 | + options = extra_options["outputs"].get("prometheus_client", {}) |
76 | + listen = options.pop("listen", None) |
77 | + if not listen: |
78 | + listen = ":{}".format(prometheus_output_port) |
79 | + elif int(listen.split(":", 1)[1]) != prometheus_output_port: |
80 | + hookenv.log( |
81 | + """prometheus_output_port is {}, but extra_options would set it |
82 | + to {}. Choosing {} from prometheus_output_port.""".format( |
83 | + prometheus_output_port, |
84 | + int(listen.split(":", 1)[1]), |
85 | + prometheus_output_port, |
86 | + ), |
87 | + level=hookenv.WARNING, |
88 | + ) |
89 | + listen = "{}:{}".format(listen.split(":", 1)[0], prometheus_output_port) |
90 | + |
91 | + return { |
92 | + "listen": listen, |
93 | + "extra_options": render_extra_options( |
94 | + "outputs", "prometheus_client", extra_options=extra_options |
95 | + ), |
96 | + } |
97 | + |
98 | + |
99 | +def render_prometheus_client_config(port): |
100 | + config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus_client") |
101 | + hookenv.log( |
102 | + "Updating {} plugin config file. Port is {}".format("prometheus_client", port), |
103 | + level=hookenv.INFO, |
104 | + ) |
105 | + context = generate_prometheus_output_config(port) |
106 | + render( |
107 | + source="prometheus_client.tmpl", |
108 | + templates_dir=get_templates_dir(), |
109 | + target=config_path, |
110 | + context=context, |
111 | + ) |
112 | + |
113 | + |
114 | @when("prometheus-client.available") |
115 | -@when("telegraf.installed") |
116 | -def prometheus_client(prometheus): |
117 | - template = """ |
118 | -[[outputs.prometheus_client]] |
119 | - listen = "{{ listen }}" |
120 | -""" |
121 | +@when_not("prometheus-client.relation.configured") |
122 | +def configure_prometheus_client_with_relation(prometheus): |
123 | + hookenv.log( |
124 | + "Configuring prometheus_client output plugin, with prometheus-client relation", |
125 | + level=hookenv.DEBUG, |
126 | + ) |
127 | + port = get_prometheus_port() or "9126" |
128 | + # We'll iterate through the prometheus-client relation counterparts, |
129 | + # inform them of our address so that they scrape it, and get their egress subnets |
130 | + # so that we can allow them |
131 | + remote_egress_subnets = [] |
132 | for relation_id in hookenv.relation_ids("prometheus-client"): |
133 | # if juju 2.x+ then we'll attempt to get the network space address |
134 | try: |
135 | - hookenv.log("Network Info") |
136 | + hookenv.log("Getting local network info", level=hookenv.DEBUG) |
137 | network_info = hookenv.network_get( |
138 | "prometheus-client", relation_id=relation_id |
139 | ) |
140 | - hookenv.log(network_info) |
141 | + hookenv.log(network_info, level=hookenv.DEBUG) |
142 | if "ingress-addresses" in network_info: |
143 | ip_addr = network_info.get("ingress-addresses")[0] |
144 | else: |
145 | ip_addr = hookenv.network_get_primary_address("prometheus-client") |
146 | + for unit in hookenv.related_units(relation_id): |
147 | + hookenv.log( |
148 | + "Getting remote egress subnet for relation {} - {}".format( |
149 | + unit, relation_id |
150 | + ), |
151 | + level=hookenv.DEBUG, |
152 | + ) |
153 | + remote_egress_subnets.append( |
154 | + hookenv.relation_get("egress-subnets", unit, relation_id) |
155 | + ) |
156 | except NotImplementedError: |
157 | # if that fails, just let prometheus.configure(...) do it's default |
158 | ip_addr = None |
159 | - if get_prometheus_port(): |
160 | - hookenv.log("Prometheus configured globally, skipping plugin setup") |
161 | - prometheus.configure( |
162 | - get_prometheus_port(), hostname=ip_addr, private_address=ip_addr |
163 | - ) |
164 | - set_flag("prometheus-client.configured") |
165 | - # bail out, nothing more need to be configured here |
166 | - return |
167 | - port = 9126 |
168 | - extra_options = get_extra_options() |
169 | - options = extra_options["outputs"].get("prometheus-client", {}) |
170 | - listen = options.pop("listen", None) |
171 | - if listen is not None: |
172 | - hookenv.log( |
173 | - "Configuring prometheus_client plugin to listen on: '{}'".format(listen) |
174 | - ) |
175 | - port = int(listen.split(":", 1)[1]) |
176 | - else: |
177 | - listen = ":{}".format(port) |
178 | - check_prometheus_port("prometheus_output", port) |
179 | prometheus.configure(port, hostname=ip_addr, private_address=ip_addr) |
180 | - config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus-client") |
181 | - hookenv.log("Updating {} plugin config file".format("prometheus-client")) |
182 | - context = {"listen": listen} |
183 | - content = render_template(template, context) + render_extra_options( |
184 | - "outputs", "prometheus_client", extra_options=extra_options |
185 | - ) |
186 | - host.write_file(config_path, content.encode("utf-8")) |
187 | + check_prometheus_port("prometheus_output", port) |
188 | + render_prometheus_client_config(port) |
189 | + set_flag("plugins.prometheus-client.configured") |
190 | + set_flag("prometheus-client.relation.configured") |
191 | + set_flag("telegraf.needs_reload") |
192 | + |
193 | + |
194 | +@when_not("prometheus-client.available") |
195 | +@when_not("plugins.prometheus-client.configured") |
196 | +def configure_prometheus_client(): |
197 | + hookenv.log("Configuring prometheus_client output plugin", level=hookenv.DEBUG) |
198 | + if get_prometheus_port(): |
199 | + port = get_prometheus_port() |
200 | + else: |
201 | + # No relation to prometheus, no port configured: do not configure the plugin |
202 | set_flag("plugins.prometheus-client.configured") |
203 | - set_flag("telegraf.needs_reload") |
204 | - set_flag("prometheus-client.configured") |
205 | + return |
206 | + check_prometheus_port("prometheus_output", port) |
207 | + render_prometheus_client_config(port) |
208 | + set_flag("plugins.prometheus-client.configured") |
209 | + set_flag("telegraf.needs_reload") |
210 | + clear_flag("prometheus-client.relation.configured") |
211 | |
212 | |
213 | def convert_days(time_string): |
214 | @@ -1317,17 +1379,15 @@ def render_prometheus_rules(prometheus_rules): |
215 | |
216 | |
217 | @when_not("prometheus-client.available") |
218 | -@when("plugins.prometheus-client.configured") |
219 | +@when("prometheus-client.relation.configured") |
220 | def prometheus_client_departed(): |
221 | hookenv.log("prometheus-client relation not available") |
222 | - config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus-client") |
223 | + config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus_client") |
224 | rels = hookenv.relations_of_type("prometheus-client") |
225 | if not rels and os.path.exists(config_path): |
226 | hookenv.log("Deleting {} plugin config file".format("prometheus-client")) |
227 | os.unlink(config_path) |
228 | clear_flag("plugins.prometheus-client.configured") |
229 | - set_flag("telegraf.needs_reload") |
230 | - clear_flag("prometheus-client.configured") |
231 | |
232 | |
233 | @when( |
234 | @@ -1406,6 +1466,8 @@ def grafana_dashboard_import_failed(): |
235 | |
236 | |
237 | @when("telegraf.needs_reload") |
238 | +@when("telegraf.installed") |
239 | +@when("telegraf.configured") |
240 | def start_or_restart(): |
241 | states = sorted( |
242 | [ |
243 | diff --git a/src/templates/prometheus_client.tmpl b/src/templates/prometheus_client.tmpl |
244 | new file mode 100644 |
245 | index 0000000..add2099 |
246 | --- /dev/null |
247 | +++ b/src/templates/prometheus_client.tmpl |
248 | @@ -0,0 +1,3 @@ |
249 | +[[outputs.prometheus_client]] |
250 | + listen = "{{ listen }}" |
251 | +{%- if extra_options %}{{ extra_options }}{%- endif %} |
252 | diff --git a/src/templates/telegraf.conf.tmpl b/src/templates/telegraf.conf.tmpl |
253 | index af59ed5..966b4a9 100644 |
254 | --- a/src/templates/telegraf.conf.tmpl |
255 | +++ b/src/templates/telegraf.conf.tmpl |
256 | @@ -80,12 +80,6 @@ |
257 | |
258 | {{ outputs }} |
259 | |
260 | -{% if prometheus_output_port %} |
261 | -[[outputs.prometheus_client]] |
262 | - listen = ":{{ prometheus_output_port }}" |
263 | - {%- if extra_options['outputs']['prometheus_client'] %}{{ render_options('prometheus_client', 'outputs', extra_options['outputs']) }}{%- endif %} |
264 | -{%- endif %} |
265 | - |
266 | ############################################################################### |
267 | # INPUTS # |
268 | ############################################################################### |
269 | diff --git a/src/tests/unit/test_telegraf.py b/src/tests/unit/test_telegraf.py |
270 | index 62a5595..d1ecd6b 100644 |
271 | --- a/src/tests/unit/test_telegraf.py |
272 | +++ b/src/tests/unit/test_telegraf.py |
273 | @@ -809,12 +809,10 @@ def test_prometheus_global(monkeypatch, config): |
274 | monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: open_ports.add(p)) |
275 | monkeypatch.setattr(telegraf.hookenv, "close_port", lambda p: open_ports.remove(p)) |
276 | config["prometheus_output_port"] = "default" |
277 | - telegraf.configure_telegraf() |
278 | - expected = """ |
279 | -[[outputs.prometheus_client]] |
280 | - listen = ":9103" |
281 | -""" |
282 | - config_file = base_dir().join("telegraf.conf") |
283 | + telegraf.configure_prometheus_client() |
284 | + expected = '''[[outputs.prometheus_client]] |
285 | + listen = ":9103"''' |
286 | + config_file = base_dir().join("telegraf.d", "prometheus_client.conf") |
287 | assert expected in config_file.read() |
288 | |
289 | |
290 | @@ -833,15 +831,13 @@ outputs: |
291 | cpu: ["cpu0"] |
292 | |
293 | """ |
294 | - telegraf.configure_telegraf() |
295 | - expected = """ |
296 | -[[outputs.prometheus_client]] |
297 | + telegraf.configure_prometheus_client() |
298 | + expected = """[[outputs.prometheus_client]] |
299 | listen = ":9103" |
300 | namedrop = ["aerospike*"] |
301 | [outputs.prometheus_client.tagpass] |
302 | - cpu = ["cpu0"] |
303 | -""" |
304 | - config_file = base_dir().join("telegraf.conf") |
305 | + cpu = ["cpu0"]""" |
306 | + config_file = os.path.join(base_dir(), "telegraf.d", "prometheus_client.conf") |
307 | assert expected in config_file.read() |
308 | |
309 | |
310 | @@ -1132,11 +1128,13 @@ def test_influxdb_api_output(monkeypatch, config): |
311 | |
312 | |
313 | def test_prometheus_client_output(mocker, monkeypatch, config): |
314 | - config["prometheus_output_port"] = "" # Not enabled globally |
315 | + config["prometheus_output_port"] = "" # Not configured globally |
316 | monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: None) |
317 | |
318 | relation_ids = ["prometheus-client:0"] |
319 | + related_units = ["prometheus/0"] |
320 | monkeypatch.setattr(telegraf.hookenv, "relation_ids", lambda r: relation_ids) |
321 | + monkeypatch.setattr(telegraf.hookenv, "related_units", lambda r: related_units) |
322 | |
323 | network_get_primary_address = mocker.patch.object( |
324 | telegraf.hookenv, "network_get_primary_address", return_value="foo" |
325 | @@ -1145,32 +1143,33 @@ def test_prometheus_client_output(mocker, monkeypatch, config): |
326 | mocker.patch.object( |
327 | telegraf.hookenv, "network_get", return_value={"ingress_addresses": ["1.2.3.4"]} |
328 | ) |
329 | + mocker.patch.object(telegraf.hookenv, "relation_get", return_value="5.6.7.8/32") |
330 | |
331 | interface = mocker.Mock(spec=RelationBase) |
332 | interface.configure = mocker.Mock() |
333 | - telegraf.prometheus_client(interface) |
334 | + telegraf.configure_prometheus_client_with_relation(interface) |
335 | expected = """ |
336 | [[outputs.prometheus_client]] |
337 | listen = ":9126" |
338 | """ |
339 | assert ( |
340 | - configs_dir().join("prometheus-client.conf").read().strip() == expected.strip() |
341 | + configs_dir().join("prometheus_client.conf").read().strip() == expected.strip() |
342 | ) |
343 | network_get_primary_address.assert_called_once_with("prometheus-client") |
344 | interface.configure.assert_called_once_with( |
345 | - 9126, hostname="foo", private_address="foo" |
346 | + "9126", hostname="foo", private_address="foo" |
347 | ) |
348 | |
349 | |
350 | def test_prometheus_client_output_departed(mocker, monkeypatch, config): |
351 | - configs_dir().join("prometheus-client.conf").write("empty") |
352 | + configs_dir().join("prometheus_client.conf").write("empty") |
353 | relations = [1] |
354 | monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations) |
355 | telegraf.prometheus_client_departed() |
356 | - assert configs_dir().join("prometheus-client.conf").exists() |
357 | + assert configs_dir().join("prometheus_client.conf").exists() |
358 | relations.pop() |
359 | telegraf.prometheus_client_departed() |
360 | - assert not configs_dir().join("prometheus-client.conf").exists() |
361 | + assert not configs_dir().join("prometheus_client.conf").exists() |
362 | |
363 | |
364 | # Integration tests (kind of) |
365 | @@ -1264,15 +1263,16 @@ def test_restart_on_output_plugin_relation_departed(mocker, monkeypatch, config) |
366 | ) |
367 | config["prometheus_output_port"] = "" |
368 | bus.discover() |
369 | + set_flag("telegraf.installed") |
370 | set_flag("snap.telegraf.installed") |
371 | set_flag("telegraf.configured") |
372 | interface = mocker.Mock(spec=RelationBase) |
373 | interface.configure = mocker.Mock() |
374 | - telegraf.prometheus_client(interface) |
375 | - assert configs_dir().join("prometheus-client.conf").exists() |
376 | + telegraf.configure_prometheus_client_with_relation(interface) |
377 | + assert configs_dir().join("prometheus_client.conf").exists() |
378 | # dispatch, file should be gone and telegraf restarted. |
379 | bus.dispatch() |
380 | - assert not configs_dir().join("prometheus-client.conf").exists() |
381 | + assert not configs_dir().join("prometheus_client.conf").exists() |
382 | service_restart.assert_called_with(telegraf.DEB_SERVICE) |
383 | |
384 |
passes make test