Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions bin/lcmspy
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
# current script dir + ..dimos


script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

python $script_dir/../dimos/utils/cli/lcmspy_cli.py "$@"
32 changes: 24 additions & 8 deletions dimos/protocol/service/lcmservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import sys
import threading
import traceback
import os
from functools import cache
from dataclasses import dataclass
from typing import Any, Callable, Optional, Protocol, runtime_checkable

Expand All @@ -26,27 +28,39 @@
from dimos.protocol.service.spec import Service


@cache
def check_root() -> bool:
"""Return True if the current process is running as root (UID 0)."""
try:
return os.geteuid() == 0 # type: ignore[attr-defined]
except AttributeError:
# Platforms without geteuid (e.g. Windows) – assume non-root.
return False


def check_multicast() -> list[str]:
"""Check if multicast configuration is needed and return required commands."""
commands_needed = []

sudo = "" if check_root() else "sudo "

# Check if loopback interface has multicast enabled
try:
result = subprocess.run(["ip", "link", "show", "lo"], capture_output=True, text=True)
if "MULTICAST" not in result.stdout:
commands_needed.append("sudo ifconfig lo multicast")
commands_needed.append(f"{sudo}ifconfig lo multicast")
except Exception:
commands_needed.append("sudo ifconfig lo multicast")
commands_needed.append(f"{sudo}ifconfig lo multicast")

# Check if multicast route exists
try:
result = subprocess.run(
["ip", "route", "show", "224.0.0.0/4"], capture_output=True, text=True
)
if not result.stdout.strip():
commands_needed.append("sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev lo")
commands_needed.append(f"{sudo}route add -net 224.0.0.0 netmask 240.0.0.0 dev lo")
except Exception:
commands_needed.append("sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev lo")
commands_needed.append(f"{sudo}route add -net 224.0.0.0 netmask 240.0.0.0 dev lo")

return commands_needed

Expand All @@ -55,22 +69,24 @@ def check_buffers() -> list[str]:
"""Check if buffer configuration is needed and return required commands."""
commands_needed = []

sudo = "" if check_root() else "sudo "

# Check current buffer settings
try:
result = subprocess.run(["sysctl", "net.core.rmem_max"], capture_output=True, text=True)
current_max = int(result.stdout.split("=")[1].strip())
if current_max < 2097152:
commands_needed.append("sudo sysctl -w net.core.rmem_max=2097152")
commands_needed.append(f"{sudo}sysctl -w net.core.rmem_max=2097152")
except Exception:
commands_needed.append("sudo sysctl -w net.core.rmem_max=2097152")
commands_needed.append(f"{sudo}sysctl -w net.core.rmem_max=2097152")

try:
result = subprocess.run(["sysctl", "net.core.rmem_default"], capture_output=True, text=True)
current_default = int(result.stdout.split("=")[1].strip())
if current_default < 2097152:
commands_needed.append("sudo sysctl -w net.core.rmem_default=2097152")
commands_needed.append(f"{sudo}sysctl -w net.core.rmem_default=2097152")
except Exception:
commands_needed.append("sudo sysctl -w net.core.rmem_default=2097152")
commands_needed.append(f"{sudo}sysctl -w net.core.rmem_default=2097152")

return commands_needed

Expand Down
79 changes: 41 additions & 38 deletions dimos/protocol/service/test_lcmservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,15 @@
autoconf,
check_buffers,
check_multicast,
check_root,
)


def get_sudo_prefix() -> str:
"""Return 'sudo ' if not running as root, empty string if running as root."""
return "" if check_root() else "sudo "


def test_check_multicast_all_configured():
"""Test check_multicast when system is properly configured."""
with patch("dimos.protocol.pubsub.lcmpubsub.subprocess.run") as mock_run:
Expand Down Expand Up @@ -63,7 +69,8 @@ def test_check_multicast_missing_multicast_flag():
]

result = check_multicast()
assert result == ["sudo ifconfig lo multicast"]
sudo = get_sudo_prefix()
assert result == [f"{sudo}ifconfig lo multicast"]


def test_check_multicast_missing_route():
Expand All @@ -83,7 +90,8 @@ def test_check_multicast_missing_route():
]

result = check_multicast()
assert result == ["sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev lo"]
sudo = get_sudo_prefix()
assert result == [f"{sudo}route add -net 224.0.0.0 netmask 240.0.0.0 dev lo"]


def test_check_multicast_all_missing():
Expand All @@ -103,9 +111,10 @@ def test_check_multicast_all_missing():
]

result = check_multicast()
sudo = get_sudo_prefix()
expected = [
"sudo ifconfig lo multicast",
"sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev lo",
f"{sudo}ifconfig lo multicast",
f"{sudo}route add -net 224.0.0.0 netmask 240.0.0.0 dev lo",
]
assert result == expected

Expand All @@ -117,9 +126,10 @@ def test_check_multicast_subprocess_exception():
mock_run.side_effect = Exception("Command failed")

result = check_multicast()
sudo = get_sudo_prefix()
expected = [
"sudo ifconfig lo multicast",
"sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev lo",
f"{sudo}ifconfig lo multicast",
f"{sudo}route add -net 224.0.0.0 netmask 240.0.0.0 dev lo",
]
assert result == expected

Expand Down Expand Up @@ -151,7 +161,8 @@ def test_check_buffers_low_max_buffer():
]

result = check_buffers()
assert result == ["sudo sysctl -w net.core.rmem_max=2097152"]
sudo = get_sudo_prefix()
assert result == [f"{sudo}sysctl -w net.core.rmem_max=2097152"]


def test_check_buffers_low_default_buffer():
Expand All @@ -166,7 +177,8 @@ def test_check_buffers_low_default_buffer():
]

result = check_buffers()
assert result == ["sudo sysctl -w net.core.rmem_default=2097152"]
sudo = get_sudo_prefix()
assert result == [f"{sudo}sysctl -w net.core.rmem_default=2097152"]


def test_check_buffers_both_low():
Expand All @@ -181,9 +193,10 @@ def test_check_buffers_both_low():
]

result = check_buffers()
sudo = get_sudo_prefix()
expected = [
"sudo sysctl -w net.core.rmem_max=2097152",
"sudo sysctl -w net.core.rmem_default=2097152",
f"{sudo}sysctl -w net.core.rmem_max=2097152",
f"{sudo}sysctl -w net.core.rmem_default=2097152",
]
assert result == expected

Expand All @@ -195,9 +208,10 @@ def test_check_buffers_subprocess_exception():
mock_run.side_effect = Exception("Command failed")

result = check_buffers()
sudo = get_sudo_prefix()
expected = [
"sudo sysctl -w net.core.rmem_max=2097152",
"sudo sysctl -w net.core.rmem_default=2097152",
f"{sudo}sysctl -w net.core.rmem_max=2097152",
f"{sudo}sysctl -w net.core.rmem_default=2097152",
]
assert result == expected

Expand All @@ -212,9 +226,10 @@ def test_check_buffers_parsing_error():
]

result = check_buffers()
sudo = get_sudo_prefix()
expected = [
"sudo sysctl -w net.core.rmem_max=2097152",
"sudo sysctl -w net.core.rmem_default=2097152",
f"{sudo}sysctl -w net.core.rmem_max=2097152",
f"{sudo}sysctl -w net.core.rmem_default=2097152",
]
assert result == expected

Expand Down Expand Up @@ -267,29 +282,26 @@ def test_autoconf_with_config_needed_success():
# Command execution calls
type(
"MockResult", (), {"stdout": "success", "returncode": 0}
)(), # sudo ifconfig lo multicast
type("MockResult", (), {"stdout": "success", "returncode": 0})(), # sudo route add...
type(
"MockResult", (), {"stdout": "success", "returncode": 0}
)(), # sudo sysctl rmem_max
type(
"MockResult", (), {"stdout": "success", "returncode": 0}
)(), # sudo sysctl rmem_default
)(), # ifconfig lo multicast
type("MockResult", (), {"stdout": "success", "returncode": 0})(), # route add...
type("MockResult", (), {"stdout": "success", "returncode": 0})(), # sysctl rmem_max
type("MockResult", (), {"stdout": "success", "returncode": 0})(), # sysctl rmem_default
]

with patch("builtins.print") as mock_print:
autoconf()

sudo = get_sudo_prefix()
# Verify the expected print calls
expected_calls = [
("System configuration required. Executing commands...",),
(" Running: sudo ifconfig lo multicast",),
(f" Running: {sudo}ifconfig lo multicast",),
(" ✓ Success",),
(" Running: sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev lo",),
(f" Running: {sudo}route add -net 224.0.0.0 netmask 240.0.0.0 dev lo",),
(" ✓ Success",),
(" Running: sudo sysctl -w net.core.rmem_max=2097152",),
(f" Running: {sudo}sysctl -w net.core.rmem_max=2097152",),
(" ✓ Success",),
(" Running: sudo sysctl -w net.core.rmem_default=2097152",),
(f" Running: {sudo}sysctl -w net.core.rmem_default=2097152",),
(" ✓ Success",),
("System configuration completed.",),
]
Expand Down Expand Up @@ -318,20 +330,11 @@ def test_autoconf_with_command_failures():
# Command execution calls - first succeeds, second fails
type(
"MockResult", (), {"stdout": "success", "returncode": 0}
)(), # sudo ifconfig lo multicast
)(), # ifconfig lo multicast
subprocess.CalledProcessError(
1,
[
"sudo",
"route",
"add",
"-net",
"224.0.0.0",
"netmask",
"240.0.0.0",
"dev",
"lo",
],
get_sudo_prefix().split()
+ ["route", "add", "-net", "224.0.0.0", "netmask", "240.0.0.0", "dev", "lo"],
"Permission denied",
"Operation not permitted",
),
Expand Down
Loading