Skip to content
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

refactor(IscDhclient): discover DHCP leases at distro-provided location #4683

Merged
merged 1 commit into from
Jan 11, 2024
Merged

Conversation

phsm
Copy link
Contributor

@phsm phsm commented Dec 12, 2023

Proposed Commit Message

refactor(IscDhclient): discover DHCP leases at distro-provided location

Use leases directory and lease file provided by Distro object
instead of cycling through all possible locations.

Additional Context

IscDhclient class seems to be only used by CloudStack datasource.

Test Steps

Checklist

Merge type

  • Squash merge using "Proposed Commit Message"
  • Rebase and merge unique commits. Requires commit messages per-commit each referencing the pull request number (#<PR_NUM>)

Copy link
Collaborator

@igalic igalic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me!

This part of the commit message,

This change adds allows discovering such lease files.

seems like it should be either "adds" or "allows", not both.

@phsm
Copy link
Contributor Author

phsm commented Dec 12, 2023

This looks good to me!

This part of the commit message,

This change adds allows discovering such lease files.

seems like it should be either "adds" or "allows", not both.

Thanks, fixed the typo in the commit message.

Copy link
Member

@holmanb holmanb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this @phsm!

Nice addition and tests, I'm leaning towards making that a (free)bsd check prior to adding to the list.

Justification below.

@@ -473,6 +473,7 @@ def get_dhclient_d():
"/var/lib/dhclient",
"/var/lib/dhcp",
"/var/lib/NetworkManager",
"/var/db",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm on the fence about whether to make this a (free)bsd check before adding. On one hand, I check a couple of linuxen, and some have the directory, others don't. Why check this directory on those distros? On the other hand, there were few files in that directory and only a single listdir called, so it shouldn't be "slow".

This function is one that I've previously considered breaking out into distros/ anyways, since I think /var/lib/dhcp/ and /var/lib/dhclient/ are distro-specific iirc.

Thoughts?

Copy link
Contributor Author

@phsm phsm Dec 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I briefly checked the distros/ directory: seems its purpose is to isolate distro-specific code in there. So this means that the cloud-init has a reliable way to detect which os/distro it is running on?

If yes, then its indeed better to implement this function per-distro.
Perhaps implement a method in distros.Distro that uses a class attribute with the dhclient directory such as this and override that class attribute per child distro class.

Copy link
Member

@holmanb holmanb Dec 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this means that the cloud-init has a reliable way to detect which os/distro it is running on?

Yes :) cloud-init has lots of distro-specific code. Some of it gets littered throughout shared code (which is acceptable prior to distro detection), but as much as possible keeping distro-specific code in distros/ and calling into it makes the code more modular and keeps non-distro code much cleaner.

Perhaps implement a method in distros.Distro that uses a class attribute with the dhclient directory such as this and override that class attribute per child distro class.

@phsm yes, this sounds like the right direction. I think we have a reference to the distro instance higher up that we'll just need to pass down the stack as an argument to access it in this function. Looks like in select_dhcp_client() we could pass the distro object as an argument to the client instance, assign that as an instance variable in __init__(), and then reference that later in get_dhclient_d(), which would have to change from a static method to just a normal instance method.

We can make the current directories be in the base implementation in distros/__init__.py, then the BSDs can set their own.

Therefore we can do less file checking for all distros - a win all around.

Copy link
Contributor Author

@phsm phsm Dec 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just made another commit with an example how I see it done:

  • main Distro class has two attributes: dhclient_lease_directory, dhclient_lease_file_regex defining the lease directory for lease files in a distro, and a regex helping to find those lease files in there.
  • every class of a distro that uses dhclient has those 2 attributes defined.
  • Cloudstack's get_vr_address() now detects a distro and supplies dhcp.IscDhclient.get_latest_lease() with the lease_dir an a regex.
  • there is no need for get_dhclient_d() anymore
  • Although get_latest_lease() function signature is changed, I don't see it being used anywhere except Cloudstack DS so it shouldn't break anything.

The purpose of this commit is to gather your feedback on whether I'm working in the right direction.
Also, do I detect the distro correctly here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just updated the PR with the following:

  1. Updated the distros files with dhclient lease director/regex for distros that support DHClient. I installed all of them on a virtual machine to verify the paths:
  • CentOS: updated centos.py to contain dhclient parameters for Centos 7. I assume no one uses CentOS > 7 on servers because they're EOL.
  • RHEL: updated rhel.py with dhclient parameters. To use dhclient in RHEL, dhcp=dhclient parameter must be set in NetworkManager config.
  • AlmaLinux: identical to RHEL.
  • Rocky: identical to RHEL.
  • Debian: updated debian.py with dhclient parameters.
  • Alpine: doesn't use dhclient, uses udhcpc.
  • Amazon Linux: updated amazon.py with dhclient parameters.
  • CloudLinux: identical to RHEL.
  • EuroLinux: identical to RHEL.
  • Fedora: identical to RHEL
  • FreeBSD: updated freebsd.py with dhclient parameters.
  • Gentoo: doesn't use dhcpcd, uses dhcpcd.
  • Mariner: uses systemd-networkd.
  • Miracle: identical to RHEL
  • Open Cloud OS: I couldn't even download it an ISO image to test. I assume its identical to RHEL.
  • OpenEuler: identical to RHEL
  • OpenSUSE: doesn't use dhclient, uses wicked.
  • SLES: I don't have a copy of SLES, I assume it also uses wicked.
  • Virtuozzo: I don't have a copy of it, I assume its identical to RHEL.
  • Tencentos: didn't test, assume its identical to RHEL.
  1. Tests:
  • Added tests for finding a lease in different distros that can use dhclient.
  • Removed TestGetLatestLease testcase from test_cloudstack.py in its entirety: Cloudstack tests shouldn't test obtaining DHCP lease, its already covered in test_dhcp.py

Copy link
Member

@holmanb holmanb Jan 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @phsm for the update. I think that there is a missing detail here.

doesn't use dhclient

Use of wicked / networkd / networkmanager / etc doesn't necessarily mean that dhclient isn't used. In fact, cloud-init itself uses dhclient during the local stage. Cloud-init sets up an ephemeral network so that it can reach out to the IMDS to get configuration. This allows cloud-init to write the networking configuration locally before the distro's built-in network manager is even started. That said, since CloudStack was never checking cloud-init's dedicated lease path, I think we can go ahead with what you have here.

We may want to also check the ephemeral lease if no data is found by the other checks, but I'll take care of that in a followup PR that I'm working on for dhcpcd.

Copy link
Collaborator

@igalic igalic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cloudinit/distros/rhel.py Outdated Show resolved Hide resolved
@phsm phsm changed the title fix: IscDhclient discover DHCP leases on FreeBSD refactor(IscDhclient): discover DHCP leases at distro-provided location Jan 5, 2024
@phsm
Copy link
Contributor Author

phsm commented Jan 5, 2024

Sorry for commit storm, I was struggling with the linters and the tests.

I also changed the PR description as its not just fixing Dhclient at FreeBSD anymore.

Copy link
Collaborator

@igalic igalic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks good, here's some requests for changes

cloudinit/sources/DataSourceCloudStack.py Outdated Show resolved Hide resolved
cloudinit/sources/DataSourceCloudStack.py Outdated Show resolved Hide resolved
cloudinit/sources/DataSourceCloudStack.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@igalic igalic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this.
thank you for this monumental effort

Copy link
Member

@holmanb holmanb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phsm nice work here - thanks for putting in this effort.

I left a couple of comments that I think we need to address.

cloudinit/distros/centos.py Outdated Show resolved Hide resolved
@@ -29,6 +29,12 @@ class Distro(distros.Distro):
network_script_tpl = "/etc/sysconfig/network-scripts/ifcfg-%s"
tz_local_fn = "/etc/localtime"
usr_lib_exec = "/usr/libexec"
# RHEL and derivatives use NetworkManager DHCP client by default.
Copy link
Member

@holmanb holmanb Jan 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but dhclient is still ran manually by cloud-init. I'd say that this is a reasonable directory to check, but if no leases exist there then we should fall back to the default dhclient directory (/var/lib/dhclient, I think).

Since NetworkManager starts after cloud-init runs dhclient, the more recent lease would be any NetworkManager lease

Copy link
Contributor Author

@phsm phsm Jan 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented:

  • if the distro-provided dir and regex yield nothing, then try to use the fallback dir and regex. Regex is specifically made to be quite loose (search for any file ending with .lease or .leases).
  • Tests for that behavior

Copy link
Member

@holmanb holmanb Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phsm Just looking at this change now, I realize that you made /var/lib/dhclient/ default for all distros. Sorry I missed this before. With the change as it stands, /var/lib/dhclient will be the only directory checked for distros that do not inherit from FreeBSD / RHEL / Debian, so I think that we need to account for the following:

From what I can tell, the dhclient subdirectory is a feature of RHEL derivatives and Arch.

The following distros use /var/lib/dhcp/: including Alpine, Gentoo (and derivatives I assume), Suse (and derivatives), Debian, etc.

No clue what Photon or Mariner use.

@igalic is /var/lib/dhclient is a reasonable directory for the non-FreeBSD BSDs?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll need to check.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenBSD puts it in the same place as FreeBSD:
https://man.openbsd.org/dhclient.8#FILES

NetBSD had switched to dhcpcd since 9.0. before that, they put it in the same place, https://man.netbsd.org/NetBSD-8.2/dhclient.8#FILES but with a different name

cloudinit/sources/DataSourceCloudStack.py Show resolved Hide resolved
Copy link
Member

@holmanb holmanb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work - getting close! A couple more changes requested, I'm testing this on Ec2 now.

cloudinit/net/dhcp.py Outdated Show resolved Hide resolved
Copy link
Member

@holmanb holmanb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @phsm, thanks for putting this together.

Looks good to me, so I'll merge.

If I understand correctly, cloudstack might also benefit from parsing the default lease that cloud-init gets during the ephemeral stage. I'll probably include that as part of the work I'm doing with dhcpcd.

@holmanb holmanb merged commit 1baa9ff into canonical:main Jan 11, 2024
29 checks passed
dermotbradley added a commit to dermotbradley/cloud-init that referenced this pull request Jan 17, 2024
PR canonical#4683 changes missed Alpine. This PR addresses this.
holmanb pushed a commit that referenced this pull request Jan 17, 2024
PR #4683 changes missed Alpine. This PR addresses this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants