How to ensure nfs-server is not started until it can resolve hostnames? (16.10)
Based on @muru's comment, I made a python script to wait until DNS resolution:
import socket
import time
import itertools
TIMEOUT = 30
HOSTS = ['stanford.edu', 'google.com', 'example.com']
def main():
hosts = itertools.cycle(HOSTS)
t0 = time.time()
for host in hosts:
t = time.time()
elapsed = t - t0
if elapsed > TIMEOUT:
break
try:
socket.getaddrinfo(host, None, proto=socket.IPPROTO_TCP)
print('Resolved {} at t = {}'.format(host, elapsed))
break
except socket.gaierror:
print('Could not resolve {} at t = {}'.format(host, elapsed))
time.sleep(0.25)
t = time.time()
if __name__ == '__main__':
main()
I saved that script as /etc/systemd/system/nfs-server.service.d/wait_for_dns.py
(one has to make the parent directory first), and then ran sudo systemctl edit --full nfs-server
, adding the following before other ExecStartPre lines:
ExecStartPre=/usr/bin/python3 /etc/systemd/system/nfs-server.service.d/wait_for_dns.py
This worked fine, though it certainly feels a bit hackish and could be improved in many ways. (I eventually just gave up on NFS in this context; it was more of a pain than it was worth.)
Related videos on Youtube
zachrahan
Updated on September 18, 2022Comments
-
zachrahan over 1 year
Summary: Is there a way to make sure that the NFS server isn't started by systemd until it can properly resolve client machine names specified in
/etc/exports
?Problem description: I have found that NFS shares are not made properly available after the server (running 16.10) reboots. Clients get "access denied by server" errors, until
exportfs -ra
orservice nfs-server restart
is manually run on the server. After that, everything works as expected.The server's
/etc/exports
contains only:/mnt/raidarray clientmachine(rw)
where
clientmachine
is the hostname of the NFS client machine on the local network.Problem identification: The output of
systemctl status nfs-server
(below) makes the problem clear: the name of the client can't be resolved at the time that the NFS server was started.● nfs-server.service - NFS server and services Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled Active: active (exited) since Tue 2017-01-17 16:47:38 CST; 26min ago Main PID: 1520 (code=exited, status=0/SUCCESS) Tasks: 0 (limit: 4915) CGroup: /system.slice/nfs-server.service Jan 17 16:47:38 servermachine exportfs[1511]: exportfs: Failed to resolve clientmachine Jan 17 16:47:38 servermachine systemd[1]: Started NFS server and services.
NetworkManager-wait-online.service
is enabled, which I had understood serves to make sure thatnetwork.target
(on whichnfs-server
depends) is not satisfied untilnetwork-online.target
is satisfied.Things that did not help:
In case I misunderstood what
NetworkManager-wait-online.service
does, I tried adding an explicitAfter=network-online.target
andWants=network-online.target
tonfs-server.service
. This doesn't fix anything. I see the new dependency show up insystemctl list-dependencies
, but name resolution still fails at boot. So it seems thatnetwork-online.target
doesn't guarantee that hostname resolution can happen.Some googling suggested that requiring
nss-lookup.target
would ensure that network resolution is available, but adding it as aWants
and/orAfter
dependency tonfs-server.service
doesn't fix things either!Adding a
Wants
and/orAfter
dependency onsystemd-resolved.service
instead ofnss-lookup.target
doesn't fix things either.
After adding all of these dependencies,
nfs-server
starts up very very late in the boot process (just before the desktop login things), but it still can't resolve hosts. Based onsystemd-analyze plot
, it appears thatnmbd
is wedged around this time, but I don't know if that's related.Configuration information: This is on a desktop version of kubuntu 16.10 that is basically a fresh install.
NetworkManager.service
is enabled andsystemd-networkd.service
is disabled -- I didn't change that from the default.Here is the
NetworkManager-wait-online
service definition:[Unit] Description=Network Manager Wait Online Documentation=man:nm-online(1) Requisite=NetworkManager.service After=NetworkManager.service Before=network-online.target [Service] Type=oneshot ExecStart=/usr/bin/nm-online -s -q --timeout=30 RemainAfterExit=yes [Install] WantedBy=network-online.target
As a workaround I could hard-code IP addresses instead of hostnames into
/etc/exports
or/etc/hosts
, but this seems somewhat brittle. Is there a better answer?EDIT - Update: following @muru's advice below, I tried making a script to wait to resolve hostnames -- just to see how long it takes. My script has to wait tens of seconds after
systemd-resolved
starts before it can actually resolve a host. This is very bizarre. I wonder if it's actually a local networking issue? Sounds like maybe a hard-coded (and auto-updating, perhaps, as suggested by @mark-stosberg)/etc/exports
or/etc/hosts
file is warranted.-
Admin over 7 yearsHack: Create a script which waits for successful DNS resolution, then use that as an
ExecStartPre
for thenfs-server
service -
Admin over 7 yearsWelcome to Ask Ubuntu! ;-) Could you do a
systemd-analyze plot > /tmp/systemd.svg
, post a link tosystemd.svg
and post the contents of/etc/systemd/system/network-online.target.wants/NetworkManager-wait-online.service
as well? then drop me a note @fabby -
Admin over 7 yearsHrmpf! What you already did was what I was going to propose... BTW, you should edit your question and provide the above critical info there so the next user looking at your question doesn't have to dig through the entire comment section.
-
Admin over 7 years@muru IMNSHO, your suggestion is the best one. Could you provide an answer for that??? If you ping me, I'll come back and upvote! ;-)
-
Admin over 7 yearsWhy hard-code and auto-update
/etc/hosts
instead of/etc/exports
itself? -
Admin over 7 yearsIf
/etc/exports
is hard-coded, it will just contain the raw IP addresses -- so you need a template file (or special comment lines) to store the hostname to look up. That's a reasonable solution. Alternately, if/etc/hosts
is used, that stores the hostname and IP both, and then the automatic updater would just need to revise the hostname to IP mapping. Both seem like reasonable approaches that might be useful in different situations.
-
zachrahan over 7 yearsThanks! I'm not sure which seems like a more robust / less kludgey solution: the suggestion from @muru to make a script that waits for successful name resolution as an
ExecStartPre
component ofnfs-server.service
, or make a cron script to edit/etc/hosts
with the latest DNS information for hosts of interest. Thoughts anyone? -
Mark Stosberg over 7 yearsIf you wait for successful name resolution in
ExecStartPre
, it's possibly it will take very long or maybe never happen. If you update/etc/hosts
with valid DNS entries only when valid DNS queries can be completed, the file will be maximally up to date. -
Fabby over 7 yearsCopy-paste of comments as an answer. -1
-
Mark Stosberg over 7 years@Fabby I'm not sure what you are referring to- I didn't copy/paste anything.
-
Fabby over 7 yearsA "virtual" copy-paste. You read through the comments and reworded them as an answer without adding anything of value is what I meant... ¯\_(ツ)_/¯
-
Mark Stosberg over 7 years@Fabby, No, I did not. And if someone had a great answer, they should have left it as an answer, not a comment!
-
zachrahan over 7 years@Fabby This answer was useful to me, at least, so it couldn't have been a total copy-paste of what I said. (And nobody other than I said anything about
/etc/hosts
...)The idea of automatically updating/etc/hosts
was a good one, too, and hadn't occurred to me. Plus the context of this being a common systemd bugaboo is useful. -
Fabby over 7 yearsIf the post is edited I can upvote instead of downvote... Leave one more comment after edit
-
Mark Stosberg over 7 yearsI've (trivially) editted the post.