Merge ~barryprice/charm-telegraf:split_prometheus_client_config into charm-telegraf: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)
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_output_port is set (and use that port in the relation).

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

passes make test

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
Haw Loeung (hloeung) wrote :

LGTM

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

Change successfully merged at revision 681fc188e8d79ae8420393be2b00d62d76099f7b

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/reactive/telegraf.py b/src/reactive/telegraf.py
index d8fd268..82cf10e 100644
--- a/src/reactive/telegraf.py
+++ b/src/reactive/telegraf.py
@@ -183,7 +183,14 @@ def list_config_files():
183 current_states = get_states()183 current_states = get_states()
184184
185 for plugin in list_supported_plugins():185 for plugin in list_supported_plugins():
186 if "plugins.{}.configured".format(plugin) in current_states.keys():186 # The prometheus_client plugin can be configured either from a relation or
187 # from the juju config
188 if ("plugins.{}.configured".format(plugin) in current_states.keys()) or (
189 "{}.configured".format(plugin) in current_states.keys()
190 ):
191 # The "prometheus-client" relation sets the "prometheus_client" plugin
192 if plugin == "prometheus-client":
193 plugin = "prometheus_client"
187 config_path = "{}/{}.conf".format(get_configs_dir(), plugin)194 config_path = "{}/{}.conf".format(get_configs_dir(), plugin)
188 config_files.append(config_path)195 config_files.append(config_path)
189196
@@ -527,9 +534,6 @@ def configure_telegraf(): # noqa: C901
527 )534 )
528 context["logfile"] = ""535 context["logfile"] = ""
529536
530 if get_prometheus_port():
531 context["prometheus_output_port"] = get_prometheus_port()
532 check_prometheus_port("prometheus_output", get_prometheus_port())
533 context["extra_options"] = get_extra_options()537 context["extra_options"] = get_extra_options()
534538
535 if get_socket_listener_port():539 if get_socket_listener_port():
@@ -645,6 +649,7 @@ def install_telegraf():
645649
646@when("telegraf.installed")650@when("telegraf.installed")
647@when("apt.installed.telegraf")651@when("apt.installed.telegraf")
652@when("plugins.prometheus-client.configured")
648@when_not("telegraf.configured")653@when_not("telegraf.configured")
649@when_not("telegraf.apt.configured")654@when_not("telegraf.apt.configured")
650def configure_telegraf_deb():655def configure_telegraf_deb():
@@ -653,6 +658,7 @@ def configure_telegraf_deb():
653658
654@when("telegraf.installed")659@when("telegraf.installed")
655@when("snap.installed.telegraf")660@when("snap.installed.telegraf")
661@when("plugins.prometheus-client.configured")
656@when_not("telegraf.configured")662@when_not("telegraf.configured")
657@when_not("telegraf.snap.configured")663@when_not("telegraf.snap.configured")
658def configure_telegraf_snap():664def configure_telegraf_snap():
@@ -677,6 +683,7 @@ def handle_config_changes():
677 if config.changed("extra_options"):683 if config.changed("extra_options"):
678 for plugin in list_supported_plugins():684 for plugin in list_supported_plugins():
679 clear_flag("plugins.{}.configured".format(plugin))685 clear_flag("plugins.{}.configured".format(plugin))
686 clear_flag("prometheus-client.relation.configured")
680 # if something else changed, let's reconfigure telegraf itself just in case687 # if something else changed, let's reconfigure telegraf itself just in case
681688
682 if config.changed("extra_plugins"):689 if config.changed("extra_plugins"):
@@ -689,6 +696,12 @@ def handle_config_changes():
689 ):696 ):
690 clear_flag("telegraf.installed")697 clear_flag("telegraf.installed")
691 clear_flag("extra_plugins.configured")698 clear_flag("extra_plugins.configured")
699 clear_flag("plugins.prometheus-client.configured")
700 clear_flag("prometheus-client.relation.configured")
701
702 if config.changed("prometheus_output_port"):
703 clear_flag("plugins.prometheus-client.configured")
704 clear_flag("prometheus-client.relation.configured")
692 clear_flag("telegraf.configured")705 clear_flag("telegraf.configured")
693 clear_flag("telegraf.apt.configured")706 clear_flag("telegraf.apt.configured")
694 clear_flag("telegraf.snap.configured")707 clear_flag("telegraf.snap.configured")
@@ -1207,59 +1220,108 @@ def influxdb_api_output(influxdb):
1207 set_flag("telegraf.needs_reload")1220 set_flag("telegraf.needs_reload")
12081221
12091222
1223def generate_prometheus_output_config(prometheus_output_port):
1224 # If extra_options are set for prometheus_client, let's integrate them
1225 extra_options = get_extra_options()
1226 options = extra_options["outputs"].get("prometheus_client", {})
1227 listen = options.pop("listen", None)
1228 if not listen:
1229 listen = ":{}".format(prometheus_output_port)
1230 elif int(listen.split(":", 1)[1]) != prometheus_output_port:
1231 hookenv.log(
1232 """prometheus_output_port is {}, but extra_options would set it
1233 to {}. Choosing {} from prometheus_output_port.""".format(
1234 prometheus_output_port,
1235 int(listen.split(":", 1)[1]),
1236 prometheus_output_port,
1237 ),
1238 level=hookenv.WARNING,
1239 )
1240 listen = "{}:{}".format(listen.split(":", 1)[0], prometheus_output_port)
1241
1242 return {
1243 "listen": listen,
1244 "extra_options": render_extra_options(
1245 "outputs", "prometheus_client", extra_options=extra_options
1246 ),
1247 }
1248
1249
1250def render_prometheus_client_config(port):
1251 config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus_client")
1252 hookenv.log(
1253 "Updating {} plugin config file. Port is {}".format("prometheus_client", port),
1254 level=hookenv.INFO,
1255 )
1256 context = generate_prometheus_output_config(port)
1257 render(
1258 source="prometheus_client.tmpl",
1259 templates_dir=get_templates_dir(),
1260 target=config_path,
1261 context=context,
1262 )
1263
1264
1210@when("prometheus-client.available")1265@when("prometheus-client.available")
1211@when("telegraf.installed")1266@when_not("prometheus-client.relation.configured")
1212def prometheus_client(prometheus):1267def configure_prometheus_client_with_relation(prometheus):
1213 template = """1268 hookenv.log(
1214[[outputs.prometheus_client]]1269 "Configuring prometheus_client output plugin, with prometheus-client relation",
1215 listen = "{{ listen }}"1270 level=hookenv.DEBUG,
1216"""1271 )
1272 port = get_prometheus_port() or "9126"
1273 # We'll iterate through the prometheus-client relation counterparts,
1274 # inform them of our address so that they scrape it, and get their egress subnets
1275 # so that we can allow them
1276 remote_egress_subnets = []
1217 for relation_id in hookenv.relation_ids("prometheus-client"):1277 for relation_id in hookenv.relation_ids("prometheus-client"):
1218 # if juju 2.x+ then we'll attempt to get the network space address1278 # if juju 2.x+ then we'll attempt to get the network space address
1219 try:1279 try:
1220 hookenv.log("Network Info")1280 hookenv.log("Getting local network info", level=hookenv.DEBUG)
1221 network_info = hookenv.network_get(1281 network_info = hookenv.network_get(
1222 "prometheus-client", relation_id=relation_id1282 "prometheus-client", relation_id=relation_id
1223 )1283 )
1224 hookenv.log(network_info)1284 hookenv.log(network_info, level=hookenv.DEBUG)
1225 if "ingress-addresses" in network_info:1285 if "ingress-addresses" in network_info:
1226 ip_addr = network_info.get("ingress-addresses")[0]1286 ip_addr = network_info.get("ingress-addresses")[0]
1227 else:1287 else:
1228 ip_addr = hookenv.network_get_primary_address("prometheus-client")1288 ip_addr = hookenv.network_get_primary_address("prometheus-client")
1289 for unit in hookenv.related_units(relation_id):
1290 hookenv.log(
1291 "Getting remote egress subnet for relation {} - {}".format(
1292 unit, relation_id
1293 ),
1294 level=hookenv.DEBUG,
1295 )
1296 remote_egress_subnets.append(
1297 hookenv.relation_get("egress-subnets", unit, relation_id)
1298 )
1229 except NotImplementedError:1299 except NotImplementedError:
1230 # if that fails, just let prometheus.configure(...) do it's default1300 # if that fails, just let prometheus.configure(...) do it's default
1231 ip_addr = None1301 ip_addr = None
1232 if get_prometheus_port():
1233 hookenv.log("Prometheus configured globally, skipping plugin setup")
1234 prometheus.configure(
1235 get_prometheus_port(), hostname=ip_addr, private_address=ip_addr
1236 )
1237 set_flag("prometheus-client.configured")
1238 # bail out, nothing more need to be configured here
1239 return
1240 port = 9126
1241 extra_options = get_extra_options()
1242 options = extra_options["outputs"].get("prometheus-client", {})
1243 listen = options.pop("listen", None)
1244 if listen is not None:
1245 hookenv.log(
1246 "Configuring prometheus_client plugin to listen on: '{}'".format(listen)
1247 )
1248 port = int(listen.split(":", 1)[1])
1249 else:
1250 listen = ":{}".format(port)
1251 check_prometheus_port("prometheus_output", port)
1252 prometheus.configure(port, hostname=ip_addr, private_address=ip_addr)1302 prometheus.configure(port, hostname=ip_addr, private_address=ip_addr)
1253 config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus-client")1303 check_prometheus_port("prometheus_output", port)
1254 hookenv.log("Updating {} plugin config file".format("prometheus-client"))1304 render_prometheus_client_config(port)
1255 context = {"listen": listen}1305 set_flag("plugins.prometheus-client.configured")
1256 content = render_template(template, context) + render_extra_options(1306 set_flag("prometheus-client.relation.configured")
1257 "outputs", "prometheus_client", extra_options=extra_options1307 set_flag("telegraf.needs_reload")
1258 )1308
1259 host.write_file(config_path, content.encode("utf-8"))1309
1310@when_not("prometheus-client.available")
1311@when_not("plugins.prometheus-client.configured")
1312def configure_prometheus_client():
1313 hookenv.log("Configuring prometheus_client output plugin", level=hookenv.DEBUG)
1314 if get_prometheus_port():
1315 port = get_prometheus_port()
1316 else:
1317 # No relation to prometheus, no port configured: do not configure the plugin
1260 set_flag("plugins.prometheus-client.configured")1318 set_flag("plugins.prometheus-client.configured")
1261 set_flag("telegraf.needs_reload")1319 return
1262 set_flag("prometheus-client.configured")1320 check_prometheus_port("prometheus_output", port)
1321 render_prometheus_client_config(port)
1322 set_flag("plugins.prometheus-client.configured")
1323 set_flag("telegraf.needs_reload")
1324 clear_flag("prometheus-client.relation.configured")
12631325
12641326
1265def convert_days(time_string):1327def convert_days(time_string):
@@ -1317,17 +1379,15 @@ def render_prometheus_rules(prometheus_rules):
13171379
13181380
1319@when_not("prometheus-client.available")1381@when_not("prometheus-client.available")
1320@when("plugins.prometheus-client.configured")1382@when("prometheus-client.relation.configured")
1321def prometheus_client_departed():1383def prometheus_client_departed():
1322 hookenv.log("prometheus-client relation not available")1384 hookenv.log("prometheus-client relation not available")
1323 config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus-client")1385 config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus_client")
1324 rels = hookenv.relations_of_type("prometheus-client")1386 rels = hookenv.relations_of_type("prometheus-client")
1325 if not rels and os.path.exists(config_path):1387 if not rels and os.path.exists(config_path):
1326 hookenv.log("Deleting {} plugin config file".format("prometheus-client"))1388 hookenv.log("Deleting {} plugin config file".format("prometheus-client"))
1327 os.unlink(config_path)1389 os.unlink(config_path)
1328 clear_flag("plugins.prometheus-client.configured")1390 clear_flag("plugins.prometheus-client.configured")
1329 set_flag("telegraf.needs_reload")
1330 clear_flag("prometheus-client.configured")
13311391
13321392
1333@when(1393@when(
@@ -1406,6 +1466,8 @@ def grafana_dashboard_import_failed():
14061466
14071467
1408@when("telegraf.needs_reload")1468@when("telegraf.needs_reload")
1469@when("telegraf.installed")
1470@when("telegraf.configured")
1409def start_or_restart():1471def start_or_restart():
1410 states = sorted(1472 states = sorted(
1411 [1473 [
diff --git a/src/templates/prometheus_client.tmpl b/src/templates/prometheus_client.tmpl
1412new file mode 1006441474new file mode 100644
index 0000000..add2099
--- /dev/null
+++ b/src/templates/prometheus_client.tmpl
@@ -0,0 +1,3 @@
1[[outputs.prometheus_client]]
2 listen = "{{ listen }}"
3{%- if extra_options %}{{ extra_options }}{%- endif %}
diff --git a/src/templates/telegraf.conf.tmpl b/src/templates/telegraf.conf.tmpl
index af59ed5..966b4a9 100644
--- a/src/templates/telegraf.conf.tmpl
+++ b/src/templates/telegraf.conf.tmpl
@@ -80,12 +80,6 @@
8080
81{{ outputs }}81{{ outputs }}
8282
83{% if prometheus_output_port %}
84[[outputs.prometheus_client]]
85 listen = ":{{ prometheus_output_port }}"
86 {%- if extra_options['outputs']['prometheus_client'] %}{{ render_options('prometheus_client', 'outputs', extra_options['outputs']) }}{%- endif %}
87{%- endif %}
88
89###############################################################################83###############################################################################
90# INPUTS #84# INPUTS #
91###############################################################################85###############################################################################
diff --git a/src/tests/unit/test_telegraf.py b/src/tests/unit/test_telegraf.py
index 62a5595..d1ecd6b 100644
--- a/src/tests/unit/test_telegraf.py
+++ b/src/tests/unit/test_telegraf.py
@@ -809,12 +809,10 @@ def test_prometheus_global(monkeypatch, config):
809 monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: open_ports.add(p))809 monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: open_ports.add(p))
810 monkeypatch.setattr(telegraf.hookenv, "close_port", lambda p: open_ports.remove(p))810 monkeypatch.setattr(telegraf.hookenv, "close_port", lambda p: open_ports.remove(p))
811 config["prometheus_output_port"] = "default"811 config["prometheus_output_port"] = "default"
812 telegraf.configure_telegraf()812 telegraf.configure_prometheus_client()
813 expected = """813 expected = '''[[outputs.prometheus_client]]
814[[outputs.prometheus_client]]814 listen = ":9103"'''
815 listen = ":9103"815 config_file = base_dir().join("telegraf.d", "prometheus_client.conf")
816"""
817 config_file = base_dir().join("telegraf.conf")
818 assert expected in config_file.read()816 assert expected in config_file.read()
819817
820818
@@ -833,15 +831,13 @@ outputs:
833 cpu: ["cpu0"]831 cpu: ["cpu0"]
834832
835"""833"""
836 telegraf.configure_telegraf()834 telegraf.configure_prometheus_client()
837 expected = """835 expected = """[[outputs.prometheus_client]]
838[[outputs.prometheus_client]]
839 listen = ":9103"836 listen = ":9103"
840 namedrop = ["aerospike*"]837 namedrop = ["aerospike*"]
841 [outputs.prometheus_client.tagpass]838 [outputs.prometheus_client.tagpass]
842 cpu = ["cpu0"]839 cpu = ["cpu0"]"""
843"""840 config_file = os.path.join(base_dir(), "telegraf.d", "prometheus_client.conf")
844 config_file = base_dir().join("telegraf.conf")
845 assert expected in config_file.read()841 assert expected in config_file.read()
846842
847843
@@ -1132,11 +1128,13 @@ def test_influxdb_api_output(monkeypatch, config):
11321128
11331129
1134def test_prometheus_client_output(mocker, monkeypatch, config):1130def test_prometheus_client_output(mocker, monkeypatch, config):
1135 config["prometheus_output_port"] = "" # Not enabled globally1131 config["prometheus_output_port"] = "" # Not configured globally
1136 monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: None)1132 monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: None)
11371133
1138 relation_ids = ["prometheus-client:0"]1134 relation_ids = ["prometheus-client:0"]
1135 related_units = ["prometheus/0"]
1139 monkeypatch.setattr(telegraf.hookenv, "relation_ids", lambda r: relation_ids)1136 monkeypatch.setattr(telegraf.hookenv, "relation_ids", lambda r: relation_ids)
1137 monkeypatch.setattr(telegraf.hookenv, "related_units", lambda r: related_units)
11401138
1141 network_get_primary_address = mocker.patch.object(1139 network_get_primary_address = mocker.patch.object(
1142 telegraf.hookenv, "network_get_primary_address", return_value="foo"1140 telegraf.hookenv, "network_get_primary_address", return_value="foo"
@@ -1145,32 +1143,33 @@ def test_prometheus_client_output(mocker, monkeypatch, config):
1145 mocker.patch.object(1143 mocker.patch.object(
1146 telegraf.hookenv, "network_get", return_value={"ingress_addresses": ["1.2.3.4"]}1144 telegraf.hookenv, "network_get", return_value={"ingress_addresses": ["1.2.3.4"]}
1147 )1145 )
1146 mocker.patch.object(telegraf.hookenv, "relation_get", return_value="5.6.7.8/32")
11481147
1149 interface = mocker.Mock(spec=RelationBase)1148 interface = mocker.Mock(spec=RelationBase)
1150 interface.configure = mocker.Mock()1149 interface.configure = mocker.Mock()
1151 telegraf.prometheus_client(interface)1150 telegraf.configure_prometheus_client_with_relation(interface)
1152 expected = """1151 expected = """
1153 [[outputs.prometheus_client]]1152 [[outputs.prometheus_client]]
1154 listen = ":9126"1153 listen = ":9126"
1155"""1154"""
1156 assert (1155 assert (
1157 configs_dir().join("prometheus-client.conf").read().strip() == expected.strip()1156 configs_dir().join("prometheus_client.conf").read().strip() == expected.strip()
1158 )1157 )
1159 network_get_primary_address.assert_called_once_with("prometheus-client")1158 network_get_primary_address.assert_called_once_with("prometheus-client")
1160 interface.configure.assert_called_once_with(1159 interface.configure.assert_called_once_with(
1161 9126, hostname="foo", private_address="foo"1160 "9126", hostname="foo", private_address="foo"
1162 )1161 )
11631162
11641163
1165def test_prometheus_client_output_departed(mocker, monkeypatch, config):1164def test_prometheus_client_output_departed(mocker, monkeypatch, config):
1166 configs_dir().join("prometheus-client.conf").write("empty")1165 configs_dir().join("prometheus_client.conf").write("empty")
1167 relations = [1]1166 relations = [1]
1168 monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)1167 monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
1169 telegraf.prometheus_client_departed()1168 telegraf.prometheus_client_departed()
1170 assert configs_dir().join("prometheus-client.conf").exists()1169 assert configs_dir().join("prometheus_client.conf").exists()
1171 relations.pop()1170 relations.pop()
1172 telegraf.prometheus_client_departed()1171 telegraf.prometheus_client_departed()
1173 assert not configs_dir().join("prometheus-client.conf").exists()1172 assert not configs_dir().join("prometheus_client.conf").exists()
11741173
11751174
1176# Integration tests (kind of)1175# Integration tests (kind of)
@@ -1264,15 +1263,16 @@ def test_restart_on_output_plugin_relation_departed(mocker, monkeypatch, config)
1264 )1263 )
1265 config["prometheus_output_port"] = ""1264 config["prometheus_output_port"] = ""
1266 bus.discover()1265 bus.discover()
1266 set_flag("telegraf.installed")
1267 set_flag("snap.telegraf.installed")1267 set_flag("snap.telegraf.installed")
1268 set_flag("telegraf.configured")1268 set_flag("telegraf.configured")
1269 interface = mocker.Mock(spec=RelationBase)1269 interface = mocker.Mock(spec=RelationBase)
1270 interface.configure = mocker.Mock()1270 interface.configure = mocker.Mock()
1271 telegraf.prometheus_client(interface)1271 telegraf.configure_prometheus_client_with_relation(interface)
1272 assert configs_dir().join("prometheus-client.conf").exists()1272 assert configs_dir().join("prometheus_client.conf").exists()
1273 # dispatch, file should be gone and telegraf restarted.1273 # dispatch, file should be gone and telegraf restarted.
1274 bus.dispatch()1274 bus.dispatch()
1275 assert not configs_dir().join("prometheus-client.conf").exists()1275 assert not configs_dir().join("prometheus_client.conf").exists()
1276 service_restart.assert_called_with(telegraf.DEB_SERVICE)1276 service_restart.assert_called_with(telegraf.DEB_SERVICE)
12771277
12781278

Subscribers

People subscribed via source and target branches

to all changes: