Merge ~rmalz/charm-advanced-routing:rmalz/modify_networkd_conf into charm-advanced-routing:master

Proposed by Robert Malz
Status: Merged
Approved by: Eric Chen
Approved revision: 20c53a26e87b460f7b033ff77f8e7df790d6f159
Merged at revision: 28162e0fb93b07f3894b00ad40d2093c12bbe234
Proposed branch: ~rmalz/charm-advanced-routing:rmalz/modify_networkd_conf
Merge into: charm-advanced-routing:master
Diff against target: 102 lines (+34/-1)
3 files modified
src/lib/advanced_routing_helper.py (+20/-0)
src/tests/unit/test_AdvancedRoutingHelper.py (+12/-1)
src/tests/unit/test_actions.py (+2/-0)
Reviewer Review Type Date Requested Status
Robert Gildein Approve
Andrea Ieri Approve
🤖 prod-jenkaas-bootstack (community) continuous-integration Approve
BootStack Reviewers Pending
Review via email: mp+453785@code.launchpad.net

Commit message

configure networkd during setup

Systemd in some scenarios can remove any rules defined outside
To fix that ManageForeignRouting* configuraton has been
Set networkd configuration during charm setup to make rules persistant.

Close LP #2034029

Description of the change

Currently advanced-routing charm assumes that networkd-dispatcher will always trigger /etc/networkd-dispatcher/routable.d/95-juju_routing script on configuration change which is currently not true for all cases.

networkd-dispatcher awaits for a operational state routable to execute above script, however systemd will not trigger such signal if all interfaces are configured with static ip addresses.

To reproduce problem configure all interfaces in unit to not use dhcp settings.
If at least one interface is configured with dhcp, systemd will generate signal for it and routable.d will be called, thus reproduction will not happen.
Once configured reload networkd service or perform networkctl reload

After changes in systemd [1], any foreign rules will be removed. To workaround this following config has been added [2]
This behavior has been confirmed with https://bugs.launchpad.net/charm-advanced-routing/+bug/2034029

1- https://github.com/systemd/systemd/pull/17477/commits/0b81225e5791f660506f7db0ab88078cf296b771
2- https://github.com/systemd/systemd/pull/19287

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
Robert Malz (rmalz) wrote :

Different approach for handle this scenario would be move dependencies from networkd-dispatcher to .network configuration of systemd.
These settings are applied once service is reloaded even if interface is configured with static IPs.
This approach is a lot more riskier

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Approve (continuous-integration)
Revision history for this message
Edward Hope-Morley (hopem) wrote :

@rmalz a couple of comments:

 * can you add a unit test for this change please?

 * rather than modifying /etc/systemd/networkd.conf it would be more inline with how charms work to use a custom override in /usr/lib/systemd/network/ or perhaps /etc/systemd/network [1] e.g. /usr/lib/systemd/network/99-juju-advanced-routing.network

[1] https://wiki.archlinux.org/title/systemd-networkd#Configuration_files

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Approve (continuous-integration)
Revision history for this message
Robert Malz (rmalz) wrote :

Hey Ed,
Following proposal I have created new file based on [1].
Script will create a new file in /usr/lib/systemd/networkd.conf.d/juju-networkd.conf" and always overwrite it with:
root@juju-946413-myostmodel-21:/home/ubuntu# cat /usr/lib/systemd/networkd.conf.d/juju-networkd.conf
# This file is managed by Juju.
[Network]
ManageForeignRoutingPolicyRules=no
ManageForeignRoutes=no

I have tested this locally, works fine.

[1] https://manpages.ubuntu.com/manpages/jammy/man5/networkd.conf.5.html

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andrea Ieri (aieri) wrote :

Looks good overall, there are just some typos

review: Needs Fixing
Revision history for this message
Robert Malz (rmalz) wrote :

Comments addressed

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andrea Ieri (aieri) wrote :

@rmalz somehow I don't see the updates. 611bd22 seems identical to b67ea26

Revision history for this message
Robert Malz (rmalz) wrote :

> @rmalz somehow I don't see the updates. 611bd22 seems identical to b67ea26

Interesting, re-pushed the changes rn.

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andrea Ieri (aieri) wrote :

lgtm

review: Approve
Revision history for this message
Robert Gildein (rgildein) wrote :

LGTM

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

Change successfully merged at revision 28162e0fb93b07f3894b00ad40d2093c12bbe234

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/lib/advanced_routing_helper.py b/src/lib/advanced_routing_helper.py
2index 636729b..afa06db 100644
3--- a/src/lib/advanced_routing_helper.py
4+++ b/src/lib/advanced_routing_helper.py
5@@ -27,6 +27,9 @@ class AdvancedRoutingHelper:
6 netplan_up_dir_path = pathlib.Path("/etc/networkd-dispatcher/routable.d")
7 policy_routing_service_dir_path = pathlib.Path("/etc/systemd/system")
8 table_name_path = pathlib.Path("/etc/iproute2/rt_tables.d/juju-managed.conf")
9+ networkd_conf_path = pathlib.Path(
10+ "/usr/lib/systemd/networkd.conf.d/95-juju-networkd.conf"
11+ )
12
13 def __init__(self):
14 """Init function."""
15@@ -105,6 +108,7 @@ class AdvancedRoutingHelper:
16 cleanup_file.write("ip route flush cache\n")
17 os.chmod(str(self.common_cleanup_path), 0o755)
18
19+ self.setup_persistent_rules()
20 self.post_setup()
21
22 def apply_config(self):
23@@ -151,6 +155,22 @@ class AdvancedRoutingHelper:
24 else:
25 raise e
26
27+ def setup_persistent_rules(self):
28+ """Modify systemd config to not delete foreign rules."""
29+ hookenv.log("Changing networkd configuration", level=hookenv.INFO)
30+ conf_parent = self.networkd_conf_path.parent
31+ if not conf_parent.exists():
32+ conf_parent.mkdir(parents=True)
33+ hookenv.log("Created {}".format(conf_parent), level=hookenv.INFO)
34+ config = (
35+ "# This file is managed by Juju.\n"
36+ "[Network]\n"
37+ "ManageForeignRoutingPolicyRules=no\n"
38+ "ManageForeignRoutes=no\n"
39+ )
40+ with open(str(self.networkd_conf_path), "w") as config_file:
41+ config_file.write(config)
42+
43 @property
44 def etc_ifup_path(self):
45 """Return path to ifup etc folder based on series."""
46diff --git a/src/tests/unit/test_AdvancedRoutingHelper.py b/src/tests/unit/test_AdvancedRoutingHelper.py
47index 4dbf93f..52550c0 100644
48--- a/src/tests/unit/test_AdvancedRoutingHelper.py
49+++ b/src/tests/unit/test_AdvancedRoutingHelper.py
50@@ -11,9 +11,10 @@ class TestAdvancedRoutingHelper:
51 """Main test class."""
52
53 test_dir = pathlib.Path("/tmp/test/charm-advanced-routing")
54- test_ifup_path = test_dir / "symlink_test" / "ifup"
55+ test_networkd_conf_path = test_dir / "networkd.conf.d" / "juju-networkd.conf"
56 test_netplanup_path = test_dir / "symlink_test" / "netplanup"
57 test_cleanup_path = test_dir / "symlink_test" / "netplandown"
58+ test_ifup_path = test_dir / "symlink_test" / "ifup"
59 test_script = "test-script"
60
61 @classmethod
62@@ -64,6 +65,7 @@ class TestAdvancedRoutingHelper:
63 test_obj.routing_script_name = self.test_script
64 test_obj.common_ifup_path = self.test_dir / "if-up" / self.test_script
65 test_obj.common_cleanup_path = self.test_dir / "cleanup" / self.test_script
66+ test_obj.networkd_conf_path = self.test_networkd_conf_path
67
68 test_obj.post_setup = noop
69 routing_validator.RoutingConfigValidator.__init__ = mock.Mock(return_value=None)
70@@ -119,3 +121,12 @@ class TestAdvancedRoutingHelper:
71 # link it again
72 test_obj.symlink_force(target, link)
73 assert link.exists()
74+
75+ def test_setup_persistent_rules(self, advanced_routing_helper):
76+ """Test setup_persistent_rules."""
77+ test_obj = advanced_routing_helper
78+ test_obj.networkd_conf_path = self.test_networkd_conf_path
79+
80+ test_obj.setup_persistent_rules()
81+
82+ assert test_obj.networkd_conf_path.exists()
83diff --git a/src/tests/unit/test_actions.py b/src/tests/unit/test_actions.py
84index e07f0e3..8e39959 100644
85--- a/src/tests/unit/test_actions.py
86+++ b/src/tests/unit/test_actions.py
87@@ -9,6 +9,7 @@ class TestActions:
88 """Test suite for actions."""
89
90 test_dir = pathlib.Path("/tmp/test/charm-advanced-routing")
91+ test_networkd_conf_path = test_dir / "networkd.conf.d" / "juju-networkd.conf"
92 test_script = "test-script"
93
94 def test_action_apply_changes_apply_config(self, advanced_routing_helper):
95@@ -23,6 +24,7 @@ class TestActions:
96 test_obj.routing_script_name = self.test_script
97 test_obj.common_ifup_path = self.test_dir / "if-up" / self.test_script
98 test_obj.common_cleanup_path = self.test_dir / "cleanup" / self.test_script
99+ test_obj.networkd_conf_path = self.test_networkd_conf_path
100
101 test_obj.post_setup = noop
102 routing_validator.RoutingConfigValidator.__init__ = mock.Mock(return_value=None)

Subscribers

People subscribed via source and target branches

to all changes: