diff options
author | Devaev Maxim <[email protected]> | 2018-07-07 23:37:38 +0000 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2018-07-07 23:37:38 +0000 |
commit | 476018aeb82398afbf53d7a91e3b8e30ff0b2851 (patch) | |
tree | b790400ed29205010d702266c7da40b16293e997 | |
parent | f9a69c7467229dc1bf864d374f252b0cc9017bcd (diff) |
udev instead own bycicles
-rw-r--r-- | kvmd/kvmd/__init__.py | 7 | ||||
-rw-r--r-- | kvmd/kvmd/extras/explorehw/__init__.py | 48 | ||||
-rw-r--r-- | kvmd/kvmd/extras/explorehw/__main__.py | 2 | ||||
-rw-r--r-- | kvmd/kvmd/msd.py | 51 | ||||
-rw-r--r-- | kvmd/kvmd/streamer.py | 59 | ||||
-rwxr-xr-x | kvmd/setup.py | 2 | ||||
-rw-r--r-- | os/platforms/v1/Dockerfile.part | 3 | ||||
-rw-r--r-- | os/platforms/v1/kvmd.yaml | 5 | ||||
-rw-r--r-- | os/platforms/v1/sysctl.conf (renamed from os/platforms/v1/99-pikvm.conf) | 0 | ||||
-rw-r--r-- | os/platforms/v1/udev.rules | 4 |
10 files changed, 30 insertions, 151 deletions
diff --git a/kvmd/kvmd/__init__.py b/kvmd/kvmd/__init__.py index c4b8dc9a..422a531c 100644 --- a/kvmd/kvmd/__init__.py +++ b/kvmd/kvmd/__init__.py @@ -34,16 +34,15 @@ def main() -> None: ) msd = MassStorageDevice( - bind=str(config["msd"]["bind"]), + device_path=str(config["msd"]["device"]), init_delay=float(config["msd"]["init_delay"]), write_meta=bool(config["msd"]["write_meta"]), loop=loop, ) streamer = Streamer( - cap_power=int(config["streamer"]["pinout"].get("cap", -1)), - conv_power=int(config["streamer"]["pinout"].get("conv", -1)), - bind=str(config["streamer"].get("bind", "")), + cap_power=int(config["streamer"]["pinout"]["cap"]), + conv_power=int(config["streamer"]["pinout"]["conv"]), sync_delay=float(config["streamer"]["sync_delay"]), init_delay=float(config["streamer"]["init_delay"]), width=int(config["streamer"]["size"]["width"]), diff --git a/kvmd/kvmd/extras/explorehw/__init__.py b/kvmd/kvmd/extras/explorehw/__init__.py deleted file mode 100644 index 42ade82f..00000000 --- a/kvmd/kvmd/extras/explorehw/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -import argparse - -from ... import msd -from ... import streamer - - -# ===== -def _probe_msd(path: str) -> bool: - info = msd.explore_device(path) - if info: - print("It's a mass-storage device") - print("--------------------------") - print("Path: ", info.path) - print("Bind: ", info.bind) - print("Size: ", info.size) - print("Manufacturer:", info.manufacturer) - print("Product: ", info.product) - print("Serial: ", info.serial) - print("Image name: ", info.image_name) - assert msd.locate_by_bind(info.bind), info.bind - return bool(info) - - -def _probe_streamer(path: str) -> bool: - info = streamer.explore_device(path) - if info: - print("It's a streamer device") - print("----------------------") - print("Path: ", info.path) - print("Bind: ", info.bind) - print("Driver:", info.driver) - assert streamer.locate_by_bind(info.bind), info.bind - return bool(info) - - -def main() -> None: - parser = argparse.ArgumentParser() - parser.add_argument("device") - options = parser.parse_args() - - for probe in [ - _probe_msd, - _probe_streamer, - ]: - if probe(options.device): - break - else: - raise RuntimeError("Can't recognize device") diff --git a/kvmd/kvmd/extras/explorehw/__main__.py b/kvmd/kvmd/extras/explorehw/__main__.py deleted file mode 100644 index 031df43e..00000000 --- a/kvmd/kvmd/extras/explorehw/__main__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import main -main() diff --git a/kvmd/kvmd/msd.py b/kvmd/kvmd/msd.py index c6694cb4..4a6b2554 100644 --- a/kvmd/kvmd/msd.py +++ b/kvmd/kvmd/msd.py @@ -25,7 +25,7 @@ class MassStorageError(Exception): class IsNotOperationalError(MassStorageError): def __init__(self) -> None: - super().__init__("Missing bind for mass-storage device") + super().__init__("Missing path for mass-storage device") class AlreadyConnectedToPcError(MassStorageError): @@ -50,7 +50,6 @@ class IsBusyError(MassStorageError): class MassStorageDeviceInfo(NamedTuple): path: str - bind: str size: int manufacturer: str product: str @@ -108,10 +107,6 @@ def explore_device(path: str) -> Optional[MassStorageDeviceInfo]: except KeyError: return None - interface_device = block_device.find_parent("usb", "usb_interface") - if not interface_device: - return None - usb_device = block_device.find_parent("usb", "usb_device") if not usb_device: return None @@ -122,7 +117,6 @@ def explore_device(path: str) -> Optional[MassStorageDeviceInfo]: return MassStorageDeviceInfo( path=path, - bind=interface_device.sys_name, size=size, manufacturer=usb_device.attributes.asstring("manufacturer").strip(), product=usb_device.attributes.asstring("product").strip(), @@ -131,24 +125,11 @@ def explore_device(path: str) -> Optional[MassStorageDeviceInfo]: ) -def locate_by_bind(bind: str) -> str: - ctx = pyudev.Context() - for device in ctx.list_devices(subsystem="block"): - storage_device = device.find_parent("usb", "usb_interface") - if storage_device: - try: - device.attributes.asint("partititon") - except KeyError: - if storage_device.sys_name == bind: - return os.path.join("/dev", device.sys_name) - return "" - - def _operated_and_locked(method: Callable) -> Callable: async def wrap(self: "MassStorageDevice", *args: Any, **kwargs: Any) -> Any: if self._device_file: # pylint: disable=protected-access raise IsBusyError() - if not self._bind: # pylint: disable=protected-access + if not self._device_path: # pylint: disable=protected-access IsNotOperationalError() async with self._lock: # pylint: disable=protected-access return (await method(self, *args, **kwargs)) @@ -156,8 +137,15 @@ def _operated_and_locked(method: Callable) -> Callable: class MassStorageDevice: # pylint: disable=too-many-instance-attributes - def __init__(self, bind: str, init_delay: float, write_meta: bool, loop: asyncio.AbstractEventLoop) -> None: - self._bind = bind + def __init__( + self, + device_path: str, + init_delay: float, + write_meta: bool, + loop: asyncio.AbstractEventLoop, + ) -> None: + + self._device_path = device_path self.__init_delay = init_delay self.__write_meta = write_meta self.__loop = loop @@ -168,8 +156,8 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes self.__writed = 0 logger = get_logger(0) - if self._bind: - logger.info("Using bind %r as mass-storage device", self._bind) + if self._device_path: + logger.info("Using %r as mass-storage device", self._device_path) try: logger.info("Enabled metadata writing") loop.run_until_complete(self.connect_to_kvm(no_delay=True)) @@ -179,9 +167,9 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes else: log = logger.exception log("Mass-storage device is not operational: %s", err) - self._bind = "" + self._device_path = "" else: - logger.warning("Missing bind; mass-storage device is not operational") + logger.warning("Mass-storage device is not operational") @_operated_and_locked async def connect_to_kvm(self, no_delay: bool=False) -> None: @@ -203,7 +191,7 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes def get_state(self) -> Dict: return { - "in_operate": bool(self._bind), + "in_operate": bool(self._device_path), "connected_to": ("kvm" if self.__device_info else "server"), "is_busy": bool(self._device_file), "writed": self.__writed, @@ -255,12 +243,9 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes await self.__close_device_file() async def __reread_device_info(self) -> None: - device_path = await self.__loop.run_in_executor(None, locate_by_bind, self._bind) - if not device_path: - raise MassStorageError("Can't locate device by bind %r" % (self._bind)) - device_info = await self.__loop.run_in_executor(None, explore_device, device_path) + device_info = await self.__loop.run_in_executor(None, explore_device, self._device_path) if not device_info: - raise MassStorageError("Can't explore device %r" % (device_path)) + raise MassStorageError("Can't explore device %r" % (self._device_path)) self.__device_info = device_info async def __close_device_file(self) -> None: diff --git a/kvmd/kvmd/streamer.py b/kvmd/kvmd/streamer.py index c5e9fd41..14bf8159 100644 --- a/kvmd/kvmd/streamer.py +++ b/kvmd/kvmd/streamer.py @@ -1,14 +1,9 @@ -import os import asyncio import asyncio.subprocess from typing import List from typing import Dict -from typing import NamedTuple from typing import Optional -from typing import Any - -import pyudev from .logging import get_logger @@ -16,52 +11,11 @@ from . import gpio # ===== -class StreamerDeviceInfo(NamedTuple): - path: str - bind: str - driver: str - - -def explore_device(path: str) -> Optional[StreamerDeviceInfo]: - # udevadm info -a -p $(udevadm info -q path -n /dev/sda) - ctx = pyudev.Context() - - video_device = pyudev.Devices.from_device_file(ctx, path) - if video_device.subsystem != "video4linux": - return None - try: - if int(video_device.attributes.get("index")) != 0: - # My strange laptop configuration - return None - except ValueError: - return None - - interface_device = video_device.find_parent("usb", "usb_interface") - if not interface_device: - return None - - return StreamerDeviceInfo( - path=path, - bind=interface_device.sys_name, - driver=interface_device.driver, - ) - - -def locate_by_bind(bind: str) -> str: - ctx = pyudev.Context() - for device in ctx.list_devices(subsystem="video4linux"): - interface_device = device.find_parent("usb", "usb_interface") - if interface_device and interface_device.sys_name == bind: - return os.path.join("/dev", device.sys_name) - return "" - - class Streamer: # pylint: disable=too-many-instance-attributes def __init__( self, cap_power: int, conv_power: int, - bind: str, sync_delay: float, init_delay: float, width: int, @@ -70,11 +24,8 @@ class Streamer: # pylint: disable=too-many-instance-attributes loop: asyncio.AbstractEventLoop, ) -> None: - assert cmd, cmd - self.__cap_power = (gpio.set_output(cap_power) if cap_power > 0 else cap_power) self.__conv_power = (gpio.set_output(conv_power) if conv_power > 0 else conv_power) - self.__bind = bind self.__sync_delay = sync_delay self.__init_delay = init_delay self.__width = width @@ -132,15 +83,7 @@ class Streamer: # pylint: disable=too-many-instance-attributes while True: # pylint: disable=too-many-nested-blocks proc: Optional[asyncio.subprocess.Process] = None # pylint: disable=no-member try: - cmd_placeholders: Dict[str, Any] = {"width": self.__width, "height": self.__height} - if self.__bind: - logger.info("Using bind %r as streamer device", self.__bind) - device_path = await self.__loop.run_in_executor(None, locate_by_bind, self.__bind) - if not device_path: - raise RuntimeError("Can't locate device by bind %r" % (self.__bind)) - cmd_placeholders["device"] = device_path - cmd = [part.format(**cmd_placeholders) for part in self.__cmd] - + cmd = [part.format(width=self.__width, height=self.__height) for part in self.__cmd] proc = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, diff --git a/kvmd/setup.py b/kvmd/setup.py index 25633f4b..d0d69429 100755 --- a/kvmd/setup.py +++ b/kvmd/setup.py @@ -24,7 +24,6 @@ def main() -> None: "kvmd.extras", "kvmd.extras.cleanup", "kvmd.extras.wscli", - "kvmd.extras.explorehw", ], entry_points={ @@ -32,7 +31,6 @@ def main() -> None: "kvmd = kvmd:main", "kvmd-cleanup = kvmd.extras.cleanup:main", "kvmd-wscli = kvmd.extras.wscli:main", - "kvmd-explorehw = kvmd.extras.explorehw:main", ], }, diff --git a/os/platforms/v1/Dockerfile.part b/os/platforms/v1/Dockerfile.part index c525b8e7..566f229c 100644 --- a/os/platforms/v1/Dockerfile.part +++ b/os/platforms/v1/Dockerfile.part @@ -4,7 +4,8 @@ RUN pkg-install \ nginx COPY stages/pikvm/config.txt /boot/ -COPY stages/pikvm/99-pikvm.conf /etc/sysctl.d/ +COPY stages/pikvm/sysctl.conf /etc/sysctl.d/99-pikvm.conf +COPY stages/pikvm/udev.rules /etc/udev/rules.d/pikvm.rules COPY stages/pikvm/index.html /srv/http/ COPY stages/pikvm/kvmd.yaml /etc/ COPY stages/pikvm/nginx.conf /etc/nginx/ diff --git a/os/platforms/v1/kvmd.yaml b/os/platforms/v1/kvmd.yaml index 3f2e8751..52890551 100644 --- a/os/platforms/v1/kvmd.yaml +++ b/os/platforms/v1/kvmd.yaml @@ -24,8 +24,7 @@ kvmd: state_poll: 0.1 msd: - # FIXME: It's for laptop lol - bind: "1-2:1.0" + device: "/dev/kvmd-msd" init_delay: 2.0 write_meta: true chunk_size: 8192 @@ -46,7 +45,7 @@ kvmd: cmd: - "/usr/bin/mjpg_streamer" - "-i" - - "input_uvc.so -d /dev/video0 -e 2 -y -n -r {width}x{height}" + - "input_uvc.so -d /dev/kvmd-streamer -e 2 -y -n -r {width}x{height}" - "-o" - "output_http.so -l localhost -p 8082" diff --git a/os/platforms/v1/99-pikvm.conf b/os/platforms/v1/sysctl.conf index 71db0efc..71db0efc 100644 --- a/os/platforms/v1/99-pikvm.conf +++ b/os/platforms/v1/sysctl.conf diff --git a/os/platforms/v1/udev.rules b/os/platforms/v1/udev.rules new file mode 100644 index 00000000..99cb0e45 --- /dev/null +++ b/os/platforms/v1/udev.rules @@ -0,0 +1,4 @@ +# https://unix.stackexchange.com/questions/66901/how-to-bind-usb-device-under-a-static-name +# https://wiki.archlinux.org/index.php/Udev#Setting_static_device_names +KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux", KERNELS=="1-1.3:1.0", SYMLINK+="kvmd-streamer" +KERNEL=="sd[a-z]", SUBSYSTEM=="block", KERNELS=="1-1.4:1.0", SYMLINK+="kvmd-msd" |