8000 Prevent ping integration from delaying startup by bdraco · Pull Request #43869 · home-assistant/core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Prevent ping integration from delaying startup #43869

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

Merged
merged 26 commits into from
Mar 31, 2021

Conversation

bdraco
Copy link
Member
@bdraco bdraco commented Dec 2, 2020

Breaking change

When restarting Home Assistant, the previous ping sensor state is now
restored and then updated in the background to allow startup to proceed
without the risk of timing out.

When the user has many ping sensors, the ping integration could
timeout starting up because each ping has to happen in the
executor.

Proposed change

Now that icmplib does not require root for newer kernels, we
can use it if the can_use_icmp_lib_with_privilege test passes
with privileged=False

The startup time problem with ping has been solved by
restoring the previous state instead of waiting for the ping to run
before starting.

NameLookupError is now handled to avoid the log filling up
when a host is offline.

device_tracker now uses multiping when possible to avoid
tying up the executor when there are many hosts.

ValentinBELYN/icmplib@v2.0.2...v2.1.1

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Example entry for configuration.yaml:

# Example configuration.yaml

Additional information

Checklist

  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • The code has been formatted using Black (black --fast homeassistant tests)
  • Tests have been added to verify that the new code works.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • Untested files have been added to .coveragerc.

The integration reached or maintains the following Integration Quality Scale:

  • No score or internal
  • 🥈 Silver
  • 🥇 Gold
  • 🏆 Platinum

To help with the load of incoming pull requests:

@ValentinBELYN
Copy link
ValentinBELYN commented Dec 2, 2020

Hi @bdraco :)

To let the kernel handle some parts of the ICMP headers and thus perform the ping function without root privileges, you must set the privileged parameter to False.

You should also handle these exceptions:

  • NameLookupError
    If you pass a hostname or FQDN in parameters and it does not exist or cannot be resolved.
  • SocketPermissionError
    If the privileges are insufficient to create the socket.
    (normally not necessary to handle this exception except for Windows, details below)
  • SocketAddressError
    If the source address cannot be assigned to the socket.
    (only if you define a source address, which is not currently the case)
  • ICMPSocketError
    If another error occurs. See the ICMPv4Socket or ICMPv6Socket class for details.
    (normally not necessary to handle this exception)

The complete documentation is up to date. You can find useful information about parameters, return value, and exceptions here: https://github.com/ValentinBELYN/icmplib#ping

Finally, the privileged parameter is ignored on Windows. Indeed, Windows is not compatible. However, icmplib can be used without administrator privileges on my Windows VM. It will be necessary to ensure that this is the case for other Home Assistant installations which are based on Windows before completely removing the fallback.

@bdraco bdraco marked this pull request as draft December 2, 2020 22:54
@bdraco
Copy link
Member Author
bdraco commented Dec 2, 2020

We only support WSL for Windows (https://github.com/home-assistant/architecture/blob/master/adr/0016-home-assistant-core.md#supported-operating-systems-and-versions) so I think we can treat it the same as linux in this case.

I'll make the adjustments to handle the NameLookupError exception and set privileged=False using the original logic when we get SocketPermissionError so it should work regardless of the underly OS

@bdraco
Copy link
Member Author
bdraco commented Dec 3, 2020

Thanks @ValentinBELYN. Your feedback was very helpful. I think I've addressed the issues.

@bdraco
Copy link
Member Author
bdraco commented Dec 3, 2020

It looks like it won't work unless the OS enables it

# sysctl net.ipv4.ping_group_range
net.ipv4.ping_group_range = 1	0

@ValentinBELYN
Copy link

net.ipv4.ping_group_range is not needed with icmplib 2.0. When the privileged parameter is disabled, a DGRAM socket is used instead of a RAW socket. You can find more details about this mechanism here: https://lwn.net/Articles/420800/

Can you run the following lines to verify that the ping function can run without root privileges on your computer?

# Run these lines without root privileges
from icmplib import ping

ping('1.1.1.1', privileged=False)

If it doesn't work, can you give me the result you get by running these lines:

from icmplib.utils import platform, PLATFORM_LINUX, PLATFORM_MACOS, PLATFORM_WINDOWS

print(platform, PLATFORM_LINUX, PLATFORM_MACOS, PLATFORM_WINDOWS, sep='\n')

Thanks :)

@bdraco
Copy link
Member Author
bdraco commented Dec 3, 2020
# Run these lines without root privileges
from icmplib import ping

ping('1.1.1.1', privileged=False)
root@ha-dev:/tmp# vim test1.py
root@ha-dev:/tmp# su nobody -s /bin/bash
nobody@ha-dev:/tmp$ python3 /tmp/test1.py
[False]
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/icmplib/sockets.py", line 89, in __init__
    self._sock = self._create_socket(
  File "/usr/local/lib/python3.8/dist-packages/icmplib/sockets.py", line 448, in _create_socket
    return socket.socket(
  File "/usr/lib/python3.8/socket.py", line 231, in __init__
    _socket.socket.__init__(self, family, type, proto, fileno)
PermissionError: [Errno 13] Permission denied

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/tmp/test1.py", line 4, in <module>
    ping('1.1.1.1', privileged=False)
  File "/usr/local/lib/python3.8/dist-packages/icmplib/ping.py", line 131, in ping
    sock = ICMPv4Socket(
  File "/usr/local/lib/python3.8/dist-packages/icmplib/sockets.py", line 103, in __init__
    raise ICMPSocketError(str(err))
icmplib.exceptions.ICMPSocketError: [Errno 13] Permission denied

@bdraco
Copy link
Member Author
bdraco commented Dec 3, 2020
from icmplib.utils import platform, PLATFORM_LINUX, PLATFORM_MACOS, PLATFORM_WINDOWS

print(platform, PLATFORM_LINUX, PLATFORM_MACOS, PLATFORM_WINDOWS, sep='\n')
root@ha-dev:/tmp# vim test2.py
root@ha-dev:/tmp# su nobody -s /bin/bash
nobody@ha-dev:/tmp$ python3 test2.py
linux
True
False
False

@bdraco
Copy link
Member Author
bdraco commented Dec 3, 2020

From the first test
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_ICMP) = -1 EACCES (Permission denied)

read(3, "U\r\r\n\0\0\0\0\242\226\v^\354S\0\0\343\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 16282) = 16281
read(3, "", 1)                          = 0
close(3)                                = 0
write(1, "[False]\n", 8[False]
)                = 8
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_ICMP) = -1 EACCES (Permission denied)
write(2, "Traceback (most recent call last"..., 35Traceback (most recent call last):
) = 35
write(2, "  File \"/usr/local/lib/python3.8"..., 89  File "/usr/local/lib/python3.8/dist-packages/icmplib/sockets.py", line 89, in __init__
) = 89

@ValentinBELYN
Copy link

What is your Linux distro + version?

@ValentinBELYN
Copy link

I will investigate tomorrow. Personally on macOS 10.15 and Ubuntu 20.04 I do not encounter this problem.

@bdraco
Copy link
Member Author
bdraco commented Dec 4, 2020

What is your Linux distro + version?

Ubuntu 18.04.3 LTS (GNU/Linux 4.4.59+ x86_64)

@davet2001
Copy link
Contributor

I get exactly the same on raspbian 10/buster.

@ValentinBELYN
Copy link

Sorry for taking some time for testing. I confirm the behavior you are seeing and indeed, this is related to the net.ipv4.ping_group_range parameter. On Debian 10.6, Debian 11 (testing) and Ubuntu 18.04 LTS, the corresponding value is 1 0 which prevents all users from using datagram sockets for pinging.

On Ubuntu 20.04 LTS and later, the value is 0 2147483647, which is Ok.

I added explanations on the project page: https://github.com/ValentinBELYN/icmplib#how-to-use-the-library-without-root-privileges

Unfortunately, on operating systems that do not allow this feature by default and to use the library without root privileges, the following command is required:

$ sudo sysctl -w net.ipv4.ping_group_range='0 2147483647'

On another level, I released the version 2.0.1 to fix old bugs.

@davet2001
Copy link
Contributor

So, would it be possible to keep the drop back to the old method for the time being? Are there any other options?

@rds76
Copy link
rds76 commented Dec 14, 2020

Old ping method doesn't work well. What about to create new sensor for old style ping? Currently I'm running patched version of new ping integration with latest HA for couple of days and it work like a charm.

@ValentinBELYN
Copy link

If you want to remove the fallback, you need to make sure that the operating system allows datagram sockets to use icmplib without root privileges. One solution would be to add the following line to the /etc/sysctl.conf configuration file in the installation and update prerequisites of Home Assistant:

net.ipv4.ping_group_range='0 2147483647'

A restart or the sysctl -p command will be necessary to take this new parameter into account.

To check the current value:

$ sysctl net.ipv4.ping_group_range

I don't know why this feature is disabled by default, especially since it doesn't introduce any security breach or compatibility errors.

8000

@rds76
Copy link
rds76 commented Dec 16, 2020

@ValentinBELYN it's not issue for me, check here: #43188 (comment)
I'm already using it with updated net.ipv4.ping_group_range value, but for those that wants to use old ping version of sensor due to this limitation...

@bdraco
Copy link
Member Author
bdraco commented Dec 30, 2020

I think we can use the unpriv code in more places with the ping('1.1.1.1', privileged=False) but we have to keep both paths for now

@github-actions
Copy link

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days.
Thank you for your contributions.

@github-actions github-actions bot added the stale label Jan 29, 2021
@bdraco
Copy link
Member Author
bdraco E7EE commented Jan 29, 2021

I still need to rework this

@github-actions github-actions bot removed the stale label Jan 29, 2021
@github-actions
Copy link

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days.
Thank you for your contributions.

@bdraco bdraco changed the title Always use icmplib for ping Use icmplib on newer kernels for ping Mar 25, 2021
@bdraco bdraco changed the title Use icmplib on newer kernels for ping Prevent ping integration from delaying startup Mar 26, 2021
@bdraco bdraco marked this pull request as ready for review March 26, 2021 01:08
@bdraco
Copy link
Member Author
bdraco commented Mar 31, 2021

Been testing this for a week with device tracker and binary sensors. Startup only takes ~11s more with it vs multiple minutes before with many binary sensors.

@frenck frenck self-requested a review March 31, 2021 12:01
Copy link
Member
@frenck frenck left a comment

Choose a reason for hiding this comment

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

LGTM, thanks @bdraco 👍

@frenck frenck merged commit bee55a0 into home-assistant:dev Mar 31, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Apr 1, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
6 participants
0