Merge ~sajoupa/charm-telegraf:split_prometheus_client_config into charm-telegraf:master

Proposed by Laurent Sesquès
Status: Superseded
Proposed branch: ~sajoupa/charm-telegraf:split_prometheus_client_config
Merge into: charm-telegraf:master
Diff against target: 387 lines (+137/-73)
4 files modified
src/reactive/telegraf.py (+112/-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
Canonical IS Reviewers Pending
BootStack Reviewers Pending
Review via email: mp+397010@code.launchpad.net

This proposal has been superseded by a proposal from 2021-02-18.

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 :

passes make test

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 :

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) :

Unmerged commits

3c4a87e... by Laurent Sesquès

small fix: move flag changes to the right if stanza for config.changed

f550c15... by Laurent Sesquès

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).

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 c139276..e2c0874 100644
--- a/src/reactive/telegraf.py
+++ b/src/reactive/telegraf.py
@@ -159,7 +159,14 @@ def list_config_files():
159 current_states = get_states()159 current_states = get_states()
160160
161 for plugin in list_supported_plugins():161 for plugin in list_supported_plugins():
162 if "plugins.{}.configured".format(plugin) in current_states.keys():162 # The prometheus_client plugin can be configured either from a relation or
163 # from the juju config
164 if ("plugins.{}.configured".format(plugin) in current_states.keys()) or (
165 "{}.configured".format(plugin) in current_states.keys()
166 ):
167 # The "prometheus-client" relation sets the "prometheus_client" plugin
168 if plugin == "prometheus-client":
169 plugin = "prometheus_client"
163 config_path = "{}/{}.conf".format(get_configs_dir(), plugin)170 config_path = "{}/{}.conf".format(get_configs_dir(), plugin)
164 config_files.append(config_path)171 config_files.append(config_path)
165172
@@ -503,9 +510,6 @@ def configure_telegraf(): # noqa: C901
503 )510 )
504 context["logfile"] = ""511 context["logfile"] = ""
505512
506 if get_prometheus_port():
507 context["prometheus_output_port"] = get_prometheus_port()
508 check_prometheus_port("prometheus_output", get_prometheus_port())
509 context["extra_options"] = get_extra_options()513 context["extra_options"] = get_extra_options()
510514
511 if get_socket_listener_port():515 if get_socket_listener_port():
@@ -621,6 +625,7 @@ def install_telegraf():
621625
622@when("telegraf.installed")626@when("telegraf.installed")
623@when("apt.installed.telegraf")627@when("apt.installed.telegraf")
628@when("plugins.prometheus-client.configured")
624@when_not("telegraf.configured")629@when_not("telegraf.configured")
625@when_not("telegraf.apt.configured")630@when_not("telegraf.apt.configured")
626def configure_telegraf_deb():631def configure_telegraf_deb():
@@ -629,6 +634,7 @@ def configure_telegraf_deb():
629634
630@when("telegraf.installed")635@when("telegraf.installed")
631@when("snap.installed.telegraf")636@when("snap.installed.telegraf")
637@when("plugins.prometheus-client.configured")
632@when_not("telegraf.configured")638@when_not("telegraf.configured")
633@when_not("telegraf.snap.configured")639@when_not("telegraf.snap.configured")
634def configure_telegraf_snap():640def configure_telegraf_snap():
@@ -653,6 +659,7 @@ def handle_config_changes():
653 if config.changed("extra_options"):659 if config.changed("extra_options"):
654 for plugin in list_supported_plugins():660 for plugin in list_supported_plugins():
655 clear_flag("plugins.{}.configured".format(plugin))661 clear_flag("plugins.{}.configured".format(plugin))
662 clear_flag("prometheus-client.relation.configured")
656 # if something else changed, let's reconfigure telegraf itself just in case663 # if something else changed, let's reconfigure telegraf itself just in case
657664
658 if config.changed("extra_plugins"):665 if config.changed("extra_plugins"):
@@ -665,6 +672,12 @@ def handle_config_changes():
665 ):672 ):
666 clear_flag("telegraf.installed")673 clear_flag("telegraf.installed")
667 clear_flag("extra_plugins.configured")674 clear_flag("extra_plugins.configured")
675 clear_flag("plugins.prometheus-client.configured")
676 clear_flag("prometheus-client.relation.configured")
677
678 if config.changed("prometheus_output_port"):
679 clear_flag("plugins.prometheus-client.configured")
680 clear_flag("prometheus-client.relation.configured")
668 clear_flag("telegraf.configured")681 clear_flag("telegraf.configured")
669 clear_flag("telegraf.apt.configured")682 clear_flag("telegraf.apt.configured")
670 clear_flag("telegraf.snap.configured")683 clear_flag("telegraf.snap.configured")
@@ -1183,59 +1196,113 @@ def influxdb_api_output(influxdb):
1183 set_flag("telegraf.needs_reload")1196 set_flag("telegraf.needs_reload")
11841197
11851198
1199def generate_prometheus_output_config(prometheus_output_port):
1200 # If extra_options are set for prometheus_client, let's integrate them
1201 extra_options = get_extra_options()
1202 options = extra_options["outputs"].get("prometheus_client", {})
1203 listen = options.pop("listen", None)
1204 if not listen:
1205 listen = ":{}".format(prometheus_output_port)
1206 elif int(listen.split(":", 1)[1]) != prometheus_output_port:
1207 hookenv.log(
1208 """prometheus_output_port is {}, but extra_options would set it
1209 to {}. Choosing {} from prometheus_output_port.""".format(
1210 prometheus_output_port,
1211 int(listen.split(":", 1)[1]),
1212 prometheus_output_port,
1213 ),
1214 level=hookenv.WARNING,
1215 )
1216 listen = "{}:{}".format(listen.split(":", 1)[0], prometheus_output_port)
1217
1218 return {
1219 "listen": listen,
1220 "extra_options": render_extra_options(
1221 "outputs", "prometheus_client", extra_options=extra_options
1222 ),
1223 }
1224
1225
1226def render_prometheus_client_config(port):
1227 config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus_client")
1228 hookenv.log(
1229 "Updating {} plugin config file. Port is {}".format("prometheus_client", port),
1230 level=hookenv.INFO,
1231 )
1232 context = generate_prometheus_output_config(port)
1233 render(
1234 source="prometheus_client.tmpl",
1235 templates_dir=get_templates_dir(),
1236 target=config_path,
1237 context=context,
1238 )
1239
1240
1186@when("prometheus-client.available")1241@when("prometheus-client.available")
1187@when("telegraf.installed")1242@when_not("prometheus-client.relation.configured")
1188def prometheus_client(prometheus):1243def configure_prometheus_client_with_relation(prometheus):
1189 template = """1244 hookenv.log(
1190[[outputs.prometheus_client]]1245 "Configuring prometheus_client output plugin, with prometheus-client relation",
1191 listen = "{{ listen }}"1246 level=hookenv.DEBUG,
1192"""1247 )
1248 if get_prometheus_port():
1249 port = get_prometheus_port()
1250 else:
1251 # We have a relation with prometheus, but removed the port number config.
1252 # Default to 9126.
1253 port = "9126"
1254 # We'll iterate through the prometheus-client relation counterparts,
1255 # inform them of our address so that they scrape it, and get their egress subnets
1256 # so that we can allow them
1257 remote_egress_subnets = []
1193 for relation_id in hookenv.relation_ids("prometheus-client"):1258 for relation_id in hookenv.relation_ids("prometheus-client"):
1194 # if juju 2.x+ then we'll attempt to get the network space address1259 # if juju 2.x+ then we'll attempt to get the network space address
1195 try:1260 try:
1196 hookenv.log("Network Info")1261 hookenv.log("Getting local network info", level=hookenv.DEBUG)
1197 network_info = hookenv.network_get(1262 network_info = hookenv.network_get(
1198 "prometheus-client", relation_id=relation_id1263 "prometheus-client", relation_id=relation_id
1199 )1264 )
1200 hookenv.log(network_info)1265 hookenv.log(network_info, level=hookenv.DEBUG)
1201 if "ingress-addresses" in network_info:1266 if "ingress-addresses" in network_info:
1202 ip_addr = network_info.get("ingress-addresses")[0]1267 ip_addr = network_info.get("ingress-addresses")[0]
1203 else:1268 else:
1204 ip_addr = hookenv.network_get_primary_address("prometheus-client")1269 ip_addr = hookenv.network_get_primary_address("prometheus-client")
1270 for unit in hookenv.related_units(relation_id):
1271 hookenv.log(
1272 "Getting remote egress subnet for relation {} - {}".format(
1273 unit, relation_id
1274 ),
1275 level=hookenv.DEBUG,
1276 )
1277 remote_egress_subnets.append(
1278 hookenv.relation_get("egress-subnets", unit, relation_id)
1279 )
1205 except NotImplementedError:1280 except NotImplementedError:
1206 # if that fails, just let prometheus.configure(...) do it's default1281 # if that fails, just let prometheus.configure(...) do it's default
1207 ip_addr = None1282 ip_addr = None
1208 if get_prometheus_port():
1209 hookenv.log("Prometheus configured globally, skipping plugin setup")
1210 prometheus.configure(
1211 get_prometheus_port(), hostname=ip_addr, private_address=ip_addr
1212 )
1213 set_flag("prometheus-client.configured")
1214 # bail out, nothing more need to be configured here
1215 return
1216 port = 9126
1217 extra_options = get_extra_options()
1218 options = extra_options["outputs"].get("prometheus-client", {})
1219 listen = options.pop("listen", None)
1220 if listen is not None:
1221 hookenv.log(
1222 "Configuring prometheus_client plugin to listen on: '{}'".format(listen)
1223 )
1224 port = int(listen.split(":", 1)[1])
1225 else:
1226 listen = ":{}".format(port)
1227 check_prometheus_port("prometheus_output", port)
1228 prometheus.configure(port, hostname=ip_addr, private_address=ip_addr)1283 prometheus.configure(port, hostname=ip_addr, private_address=ip_addr)
1229 config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus-client")1284 check_prometheus_port("prometheus_output", port)
1230 hookenv.log("Updating {} plugin config file".format("prometheus-client"))1285 render_prometheus_client_config(port)
1231 context = {"listen": listen}1286 set_flag("plugins.prometheus-client.configured")
1232 content = render_template(template, context) + render_extra_options(1287 set_flag("prometheus-client.relation.configured")
1233 "outputs", "prometheus_client", extra_options=extra_options1288 set_flag("telegraf.needs_reload")
1234 )1289
1235 host.write_file(config_path, content.encode("utf-8"))1290
1291@when_not("prometheus-client.available")
1292@when_not("plugins.prometheus-client.configured")
1293def configure_prometheus_client():
1294 hookenv.log("Configuring prometheus_client output plugin", level=hookenv.DEBUG)
1295 if get_prometheus_port():
1296 port = get_prometheus_port()
1297 else:
1298 # No relation to prometheus, no port configured: do not configure the plugin
1236 set_flag("plugins.prometheus-client.configured")1299 set_flag("plugins.prometheus-client.configured")
1237 set_flag("telegraf.needs_reload")1300 return
1238 set_flag("prometheus-client.configured")1301 check_prometheus_port("prometheus_output", port)
1302 render_prometheus_client_config(port)
1303 set_flag("plugins.prometheus-client.configured")
1304 set_flag("telegraf.needs_reload")
1305 clear_flag("prometheus-client.relation.configured")
12391306
12401307
1241def convert_days(time_string):1308def convert_days(time_string):
@@ -1293,17 +1360,15 @@ def render_prometheus_rules(prometheus_rules):
12931360
12941361
1295@when_not("prometheus-client.available")1362@when_not("prometheus-client.available")
1296@when("plugins.prometheus-client.configured")1363@when("prometheus-client.relation.configured")
1297def prometheus_client_departed():1364def prometheus_client_departed():
1298 hookenv.log("prometheus-client relation not available")1365 hookenv.log("prometheus-client relation not available")
1299 config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus-client")1366 config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus_client")
1300 rels = hookenv.relations_of_type("prometheus-client")1367 rels = hookenv.relations_of_type("prometheus-client")
1301 if not rels and os.path.exists(config_path):1368 if not rels and os.path.exists(config_path):
1302 hookenv.log("Deleting {} plugin config file".format("prometheus-client"))1369 hookenv.log("Deleting {} plugin config file".format("prometheus-client"))
1303 os.unlink(config_path)1370 os.unlink(config_path)
1304 clear_flag("plugins.prometheus-client.configured")1371 clear_flag("plugins.prometheus-client.configured")
1305 set_flag("telegraf.needs_reload")
1306 clear_flag("prometheus-client.configured")
13071372
13081373
1309@when(1374@when(
@@ -1382,6 +1447,8 @@ def grafana_dashboard_import_failed():
13821447
13831448
1384@when("telegraf.needs_reload")1449@when("telegraf.needs_reload")
1450@when("telegraf.installed")
1451@when("telegraf.configured")
1385def start_or_restart():1452def start_or_restart():
1386 states = sorted(1453 states = sorted(
1387 [1454 [
diff --git a/src/templates/prometheus_client.tmpl b/src/templates/prometheus_client.tmpl
1388new file mode 1006441455new 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 2cfbdc8..09e1575 100644
--- a/src/tests/unit/test_telegraf.py
+++ b/src/tests/unit/test_telegraf.py
@@ -753,12 +753,10 @@ def test_prometheus_global(monkeypatch, config):
753 monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: open_ports.add(p))753 monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: open_ports.add(p))
754 monkeypatch.setattr(telegraf.hookenv, "close_port", lambda p: open_ports.remove(p))754 monkeypatch.setattr(telegraf.hookenv, "close_port", lambda p: open_ports.remove(p))
755 config["prometheus_output_port"] = "default"755 config["prometheus_output_port"] = "default"
756 telegraf.configure_telegraf()756 telegraf.configure_prometheus_client()
757 expected = """757 expected = '''[[outputs.prometheus_client]]
758[[outputs.prometheus_client]]758 listen = ":9103"'''
759 listen = ":9103"759 config_file = base_dir().join("telegraf.d", "prometheus_client.conf")
760"""
761 config_file = base_dir().join("telegraf.conf")
762 assert expected in config_file.read()760 assert expected in config_file.read()
763761
764762
@@ -777,15 +775,13 @@ outputs:
777 cpu: ["cpu0"]775 cpu: ["cpu0"]
778776
779"""777"""
780 telegraf.configure_telegraf()778 telegraf.configure_prometheus_client()
781 expected = """779 expected = """[[outputs.prometheus_client]]
782[[outputs.prometheus_client]]
783 listen = ":9103"780 listen = ":9103"
784 namedrop = ["aerospike*"]781 namedrop = ["aerospike*"]
785 [outputs.prometheus_client.tagpass]782 [outputs.prometheus_client.tagpass]
786 cpu = ["cpu0"]783 cpu = ["cpu0"]"""
787"""784 config_file = base_dir().join("telegraf.d", "prometheus_client.conf")
788 config_file = base_dir().join("telegraf.conf")
789 assert expected in config_file.read()785 assert expected in config_file.read()
790786
791787
@@ -1076,11 +1072,13 @@ def test_influxdb_api_output(monkeypatch, config):
10761072
10771073
1078def test_prometheus_client_output(mocker, monkeypatch, config):1074def test_prometheus_client_output(mocker, monkeypatch, config):
1079 config["prometheus_output_port"] = "" # Not enabled globally1075 config["prometheus_output_port"] = "" # Not configured globally
1080 monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: None)1076 monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: None)
10811077
1082 relation_ids = ["prometheus-client:0"]1078 relation_ids = ["prometheus-client:0"]
1079 related_units = ["prometheus/0"]
1083 monkeypatch.setattr(telegraf.hookenv, "relation_ids", lambda r: relation_ids)1080 monkeypatch.setattr(telegraf.hookenv, "relation_ids", lambda r: relation_ids)
1081 monkeypatch.setattr(telegraf.hookenv, "related_units", lambda r: related_units)
10841082
1085 network_get_primary_address = mocker.patch.object(1083 network_get_primary_address = mocker.patch.object(
1086 telegraf.hookenv, "network_get_primary_address", return_value="foo"1084 telegraf.hookenv, "network_get_primary_address", return_value="foo"
@@ -1089,32 +1087,33 @@ def test_prometheus_client_output(mocker, monkeypatch, config):
1089 mocker.patch.object(1087 mocker.patch.object(
1090 telegraf.hookenv, "network_get", return_value={"ingress_addresses": ["1.2.3.4"]}1088 telegraf.hookenv, "network_get", return_value={"ingress_addresses": ["1.2.3.4"]}
1091 )1089 )
1090 mocker.patch.object(telegraf.hookenv, "relation_get", return_value="5.6.7.8/32")
10921091
1093 interface = mocker.Mock(spec=RelationBase)1092 interface = mocker.Mock(spec=RelationBase)
1094 interface.configure = mocker.Mock()1093 interface.configure = mocker.Mock()
1095 telegraf.prometheus_client(interface)1094 telegraf.configure_prometheus_client_with_relation(interface)
1096 expected = """1095 expected = """
1097 [[outputs.prometheus_client]]1096 [[outputs.prometheus_client]]
1098 listen = ":9126"1097 listen = ":9126"
1099"""1098"""
1100 assert (1099 assert (
1101 configs_dir().join("prometheus-client.conf").read().strip() == expected.strip()1100 configs_dir().join("prometheus_client.conf").read().strip() == expected.strip()
1102 )1101 )
1103 network_get_primary_address.assert_called_once_with("prometheus-client")1102 network_get_primary_address.assert_called_once_with("prometheus-client")
1104 interface.configure.assert_called_once_with(1103 interface.configure.assert_called_once_with(
1105 9126, hostname="foo", private_address="foo"1104 "9126", hostname="foo", private_address="foo"
1106 )1105 )
11071106
11081107
1109def test_prometheus_client_output_departed(mocker, monkeypatch, config):1108def test_prometheus_client_output_departed(mocker, monkeypatch, config):
1110 configs_dir().join("prometheus-client.conf").write("empty")1109 configs_dir().join("prometheus_client.conf").write("empty")
1111 relations = [1]1110 relations = [1]
1112 monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)1111 monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
1113 telegraf.prometheus_client_departed()1112 telegraf.prometheus_client_departed()
1114 assert configs_dir().join("prometheus-client.conf").exists()1113 assert configs_dir().join("prometheus_client.conf").exists()
1115 relations.pop()1114 relations.pop()
1116 telegraf.prometheus_client_departed()1115 telegraf.prometheus_client_departed()
1117 assert not configs_dir().join("prometheus-client.conf").exists()1116 assert not configs_dir().join("prometheus_client.conf").exists()
11181117
11191118
1120# Integration tests (kind of)1119# Integration tests (kind of)
@@ -1208,15 +1207,16 @@ def test_restart_on_output_plugin_relation_departed(mocker, monkeypatch, config)
1208 )1207 )
1209 config["prometheus_output_port"] = ""1208 config["prometheus_output_port"] = ""
1210 bus.discover()1209 bus.discover()
1210 set_flag("telegraf.installed")
1211 set_flag("snap.telegraf.installed")1211 set_flag("snap.telegraf.installed")
1212 set_flag("telegraf.configured")1212 set_flag("telegraf.configured")
1213 interface = mocker.Mock(spec=RelationBase)1213 interface = mocker.Mock(spec=RelationBase)
1214 interface.configure = mocker.Mock()1214 interface.configure = mocker.Mock()
1215 telegraf.prometheus_client(interface)1215 telegraf.configure_prometheus_client_with_relation(interface)
1216 assert configs_dir().join("prometheus-client.conf").exists()1216 assert configs_dir().join("prometheus_client.conf").exists()
1217 # dispatch, file should be gone and telegraf restarted.1217 # dispatch, file should be gone and telegraf restarted.
1218 bus.dispatch()1218 bus.dispatch()
1219 assert not configs_dir().join("prometheus-client.conf").exists()1219 assert not configs_dir().join("prometheus_client.conf").exists()
1220 service_restart.assert_called_with(telegraf.DEB_SERVICE)1220 service_restart.assert_called_with(telegraf.DEB_SERVICE)
12211221
12221222

Subscribers

People subscribed via source and target branches

to all changes: