-
Notifications
You must be signed in to change notification settings - Fork 519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
netdog: Add systemd-networkd config generation #3266
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With all the extra conditional compilation, I just want to confirm we have run clippy
and others for both sides of netdog with and without systemd-networkd enabled to ensure the wicked stuff still builds how we expect. It was hard to track all those changes and hopefully our tools will help us catch any missing bits.
b35faae
to
a055b89
Compare
^ Addresses @yeazelm 's comments. Thanks! |
Also, I confirmed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀
// Destructure self to ensure we don't skip any fields (unless we want to) | ||
let Self { | ||
name, | ||
dhcp4: _, | ||
dhcp6: _, | ||
static4: _, | ||
static6: _, | ||
routes: _, | ||
device: _, | ||
id, | ||
} = self; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is "what" rather than "why" - it's obvious that some fields are skipped but it's not clear why.
For example, we never use the device
field for a NetworkDVlan
but I don't know why. If we never use it, why do we even have that field?
What failure case are you actually concerned about defending against here and is there a different mechanism we can use instead?
The destructuring itself is OK, at least for functions where we use more of the fields - it's kind of excessive here - but the comment implies something is being ensured and I don't follow what that is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll update the comment.
For example, we never use the device field for a NetworkDVlan but I don't know why. If we never use it, why do we even have that field?
The device field gets used to create the map of devices -> VLANs. It doesn't directly get used to create files for the VLAN itself. I'll add a comment explaining that.
What failure case are you actually concerned about defending against here and is there a different mechanism we can use instead?
Basically I was trying to defend against the future addition of fields to the NetworkDVlan
struct that accidentally don't get used to create files. If we destructure, the compiler would yell about a specific field not being used, at which point the dev could decide if it's needed or not.
[Match] | ||
Name=eno1 | ||
[Link] | ||
RequiredForOnline=true | ||
[Network] | ||
DHCP=ipv4 | ||
IPv6AcceptRA=true | ||
[DHCPv4] | ||
UseDNS=true | ||
UseDomains=true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: it'd be great if we could separate sections with empty lines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that should be doable via our macro - will look into it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could blindly emit a newline before new section headings in the macro. That would leave a newline at the beginning of the file.
I haven't figured out a "smarter" way, given the macro uses repetition to generate all the sections in order. AFAIK, there's not really a way to enumerate/index during that repetition.
a055b89
to
0c455be
Compare
^ The above addresses all of @cbgbt and @bcressey 's comments except for one:
@bcressey's comment caused me to re-examine why i created a different With |
0c455be
to
bfdb8a7
Compare
^ The above push addresses the couple issues we had identified in my last comment:
This push adds an additional commit, which includes a new type parameter for the builder for |
@@ -143,7 +143,7 @@ via = "2001:beef:beef::1" | |||
{{#if (eq version 3)}} | |||
[myvlan] | |||
kind = "vlan" | |||
device = "eno1" | |||
device = "eno100" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This device was changed to eno100 because for systemd-networkd
we expect to generate a file for this link. Since we already have (and validate) an eno1
in this config, we need to change the name in order to generate and validate a different file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this point to a bug in the wicked
backend rendering? It seems like an error to generate eno1.xml
and myvlan.xml
that both reference the same device.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wicked
is the opposite of systemd-networkd
in that the interface's config file doesn't include the VLAN. The VLAN's config file includes the interface name. Since we're now using the same net_config.toml
, we have to use a different interface name since there's already eno1
in the file that is not a member of the VLAN.
The above commit adds an additional integration test to handle the case where a device is a member of a VLAN, but also has it's own addressing config. Our current set of integration tests only covered the case where the underlying interface was only used for the VLAN. |
2881098
to
dc21411
Compare
^ Oops - forgot to add the wicked reference files for the additional integration test. Added those |
@@ -7,7 +7,7 @@ use super::Result; | |||
pub(crate) use netdev::{NetDevBuilder, NetDevConfig}; | |||
pub(crate) use network::{NetworkBuilder, NetworkConfig}; | |||
|
|||
const NETWORKD_CONFIG_DIR: &str = "/etc/systemd/network"; | |||
const NETWORKD_CONFIG_DIR: &str = "/run/systemd/network"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love this change - there are a lot more protections on /etc
. Why is this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than writing to /run
, I've changed it back to /etc/systemd/networkd
, and am creating that directory via mount unit with the correct context attached.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't done much yet with Bottlerocket's mounts, but isn't /etc
already mounted as tmpfs? Why do we need an additional mount?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed /etc
is mounted as a tmpfs. We need the directory /etc/systemd/network
to be created, but because systemd-networkd
runs with DefaultDependencies=no
(which includes local-fs), we can't use tmpfiles.d to help us there. A mount unit also allows us to create the directory with the proper SELinux label.
I'm open to suggestions if there's a better way that handles the timing issue we have!
dc21411
to
b157308
Compare
^ The above push addresses @bcressey 's comments! |
b157308
to
0089638
Compare
^ Changes the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall, some minor quibbles with the new unit's dependencies.
Description=systemd-networkd configuration directory | ||
DefaultDependencies=no | ||
Conflicts=umount.target | ||
Before=generate-network-config.service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to add the standard mount unit dependencies:
Before=generate-network-config.service | |
Before=local-fs.target umount.target generate-network-config.service |
But I'd really prefer that we used RequiresMountsFor
in generate-network-config.service
instead. Consider doing that in a drop-in for that unit that's added for %{with systemd_networkd}
.
Options=nosuid,nodev,noexec,noatime,context=system_u:object_r:lease_t:s0,mode=0755 | ||
|
||
[Install] | ||
RequiredBy=systemd-networkd.service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A judgment call but I prefer "WantedBy" unless the other service can't possibly work without this.
RequiredBy=systemd-networkd.service | |
WantedBy=systemd-networkd.service |
This commit includes a new mount unit that creates the systemd-networkd configuration directory (/etc/systemd/network) at runtime with the correct SELinux context. It also adds a drop-in unit that makes the mount required by generate-network-config.service.
This commit adds a new type parameter for the NetworkBuilder type specifically for interfaces meant only to be used as the link for a VLAN. These types of interfaces are typically used for "tagged only"-type setups. The interface requires config so it can be managed and a member of a VLAN but otherwise has all DHCP and addressing turned off.
This change adds two new traits, NetDevFileCreator and NetworkFileCreator. Device structs will implement these traits if they require .netdev and/or .network files. This change also implements said traits for the three devices we currently support (bonds, vlans, interfaces). Under the hood, these implementations drive the previously added netdev/network builders.
This change adds a new type `NetworkDConfig`, which is the "top-level" interface for systemd-networkd config creation. The type can be created from any version of network config, provided the struct implements the `TryInto<NetworkDDevice>` trait. The type presents a single method `create_files()` which will drive the underlying devices to create and return a list of appropriate configuration files.
Similar to the earlier change made to wicked's config here: bottlerocket-os@91e2cc9, this commit adds a method `accept_ra()` to `NetworkConfig` that adds the "IPv6AcceptRA" entry. Once we are able to add this setting via net config, this method can be removed.
This commit puts all the pieces together to enable systemd-networkd config generation via netdog. The change adds an additional trait method to the Interfaces trait that all versions of net config must implement: `as_networkd_config()`. This method returns a `NetworkDConfig`, from which all config files may be generated. Under the hood, this method takes advantage of the TryFrom conversions also included in this commit. This commit adds the trait method to all versions of net config, and also adds integration tests to ensure we generate the expected files for each device in the proper format. These tests use the same `net_config.toml` file as the wicked integration tests.
This commit tidies up the conditional compilation by ensuring imports pertaining to wicked and systemd-networkd are behind their respective cfg blocks and in consecutive lines. This should also ease removal in the future. A few missed remaining warnings regarding unused variables were cleaned up here as well.
This commit adds an additional integration test meant to cover the case where an interface is a member of a VLAN, but also has its own addressing configuration.
0089638
to
fd7b2e1
Compare
^ Addresses @bcressey 's comments re: the mount unit / drop-in unit. Proof of the drop-in working:
|
Issue number:
Related to #2449
Description of changes:
This PR is probably best read in commit order :)
This is the grand finale, yes, the PR that puts all the pieces together for
systemd-networkd
config generation!This PR drives the previously added network/netdev config builders via the
systemd-networkd
devices structs to createsystemd-networkd
config files.It also adds a new top-level type:
NetworkDConfig
. This is the main type that gets created from net config; it contains the devices and a map of VLANs. The devices are created via conversions of the various versions of net config; these conversions are contained in the newly addedconversions.rs
.NetworkDConfig
has a methodcreate_files()
that outputs all of the necessary configuration files for all configured devices. Under the hood, each of the contained devices is driven to create the appropriate files for the device. The device structs implement traits depending on their need for.network
or.netdev
files. Inside the trait implementations, the devices drive the builders.Conditional compilation bits are also tidied up, ensuring wicked stuff isn't included anywhere in builds that don't include it.
To update the diagram from #3220 , this PR implements the left side of the diagram: the conversion of netconfig to
systemd-networkd
devices, and driving the builders to create config.Testing done:
aws-k8s-1.24
(with wicked) image to ensure nothing is broken over there: all goodaws-dev
(with systemd-networkd) image configured for early console inpreconfigured.target
, and observe the proper files being generated and network online!metal-dev
image with the followingnet.toml
and observed the box boot, not hang waiting for optional DHCP6, and both interface come up and get DHCP4 addresses. Found the proper config files in/run/systemd/network/10-{eno1,eno2}.network
. I also pulled the network cable from eno1, and observed the box wait for it to become online andsystemd-networkd-wait-online.service
fail, proving theRequiredForOnline
bit is working./etc/systemd/network
directory gets the proper context:Terms of contribution:
By submitting this pull request, I agree that this contribution is dual-licensed under the terms of both the Apache License, version 2.0, and the MIT license.