7

python-mtrpacket 在 riscv64 上编译测试不通过

 2 years ago
source link: https://blog.jiejiss.com/python-mtrpacket-%E5%9C%A8-riscv64-%E4%B8%8A%E7%BC%96%E8%AF%91%E6%B5%8B%E8%AF%95%E4%B8%8D%E9%80%9A%E8%BF%87/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

python-mtrpacket 在 riscv64 上编译测试不通过

2022-01-31

python-mtrpacket 是使用 Python 实现的异步网络探测工具。其当前版本(1.0.0-3)在 Arch Linux 主线的 x86_64 架构能正常编译通过,在 riscv64 下报错:

.E/bin/sh: line 1: mtr-packet-missing: command not found
..
======================================================================
ERROR: test_commands (__main__.TestCommands)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/build/python-mtrpacket/src/mtr-packet-python-1.0.0/test/test.py", line 210, in test_commands
asyncio_run(self.async_commands())
File "/build/python-mtrpacket/src/mtr-packet-python-1.0.0/test/test.py", line 218, in asyncio_run
return loop.run_until_complete(loop.create_task(coro))
File "/usr/lib/python3.10/asyncio/base_events.py", line 641, in run_until_complete
return future.result()
File "/build/python-mtrpacket/src/mtr-packet-python-1.0.0/test/test.py", line 203, in async_commands
async with mtrpacket.MtrPacket() as mtr:
File "/build/python-mtrpacket/src/mtr-packet-python-1.0.0/mtrpacket/__init__.py", line 138, in __aenter__
await self.open()
File "/build/python-mtrpacket/src/mtr-packet-python-1.0.0/mtrpacket/__init__.py", line 314, in open
if not await self.check_support('send-probe'):
File "/build/python-mtrpacket/src/mtr-packet-python-1.0.0/mtrpacket/__init__.py", line 368, in check_support
(_, args) = await self._command('check-support', check_args)
File "/build/python-mtrpacket/src/mtr-packet-python-1.0.0/mtrpacket/__init__.py", line 275, in _command
return await future
mtrpacket.ProcessError: failure to communicate with subprocess "./nc_mock.sh" (is it installed and in the PATH?)

----------------------------------------------------------------------
Ran 4 tests in 1.296s

FAILED (errors=1)

这里面 /bin/sh: line 1: mtr-packet-missing: command not found 是正常输出,属于第三个测试点,不用管它。研究下代码就能发现这个错误是预期行为,会被 self.assertRaises 抓到。E(错误)的是第二个测试点,本不应该出现 mtrpacket.ProcessError,但是出现了。

看一下 test/nc_mock.sh,发现很简单,就这么一点东西:

#!/bin/sh

nc localhost 8901

那这怎么就在 riscv64 上锅了呢?

首先怀疑 qemu-userargv[0] 导致找不到 nc_mock.sh,但这很容易排除。只需要在 nc_mock.sh 中加入:

sleep 30

然后发现测试在第二个点上卡住三十秒,就知道其实 nc_mock.sh 是被运行了的。由此可以确定:原本的报错提示具有误导性。

那么,既然运行了,怎么就报错了呢?修改一下 PKGBUILD(Arch Linux 编译包时使用的脚本),把 check() 中的 ./test.sh || bash -i,这样我们就在 test.sh(它会间接调用 nc_mock.sh)非零返回的时候得到进入到打包所用的 rootfs 环境的快捷通道。

之后通过修改 test/test.pymtrpacket/__init__.py,最终定位到出问题的地方:

首先是测试入口,在 test.py 里面创建了一个 mtr 的服务端,之后去启动对应的客户端。第二个测试点使用 nc_mock.sh 作为客户端:

mtr_packet_executable = os.environ.get('MTR_PACKET')  # ./nc_mock.sh
if not mtr_packet_executable:
mtr_packet_executable = 'mtr-packet'

self._subprocess_name = mtr_packet_executable
self.process = await asyncio.create_subprocess_shell(
mtr_packet_executable,
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE)

self._result_task = asyncio.ensure_future(self._dispatch_results())
self._opened = True

if not await self.check_support('send-probe'):
await self.close()

这里可以看到,创建了一个 ./nc_mock.sh 的子进程。这个子进程会通过 nc 连接到 localhost8901 端口,在这个端口上监听的是 test.py 预先创建好的服务端,于是就可以走正常测试流程了。

之后是测试流程,可以看到立马执行的是 check_support('send-probe'),追进去:

async def check_support(self, feature: str) -> bool:
check_args = {'feature': feature}
(_, args) = await self._command('check-support', check_args)

async def _command(self, command_type: str, arguments: Dict[str, str]) -> Tuple[str, Dict[str, str]]:
# ...
command_str = token + ' ' + command_type
for argument_name in arguments:
argument_value = arguments[argument_name]
command_str += ' ' + argument_name + ' ' + argument_value
command_str += '\n'

self.process.stdin.write(command_str.encode('ascii'))

到这里,就出问题了。由于 python-mtrpacketcheckdepends 依赖是 gnu-netcat,这个 netcat 在 riscv64 上的表现和 x86_64 上不一致,会提早退出。如果将 LOCALE 设置为 itsk,还能看到对应语言(意大利语 / 斯洛伐克语)的错误提示。为什么只有这两种语言呢?我也不知道,反正 Package Contents 里只有这两个:

usr/share/locale/it/
usr/share/locale/it/LC_MESSAGES/
usr/share/locale/it/LC_MESSAGES/netcat.mo
usr/share/locale/sk/
usr/share/locale/sk/LC_MESSAGES/
usr/share/locale/sk/LC_MESSAGES/netcat.mo

So…… 反正我也不关心具体报错信息了,意大利语我也看不懂。直接把 PKGBUILD 里的 checkdependsgnu-netcat 换成 openbsd-netcat 完事,反正 ./nc_mock.sh 里的简单用法还不至于触及到两个 variant 存在不兼容的黑色高级部分。

来源:https://blog.jiejiss.com/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK