SelfhostedPro / Yacht

A web interface for managing docker containers with an emphasis on templating to provide 1 click deployments. Think of it like a decentralized app store for servers that anyone can make packages for.
MIT License
3.32k stars 158 forks source link

[Bug Report] [ARM] TypeError: type NoneType doesn't define __round__ method #509

Closed denilsonsa closed 4 weeks ago

denilsonsa commented 2 years ago

Describe the bug When trying to use Yacht on a Raspberry Pi 4 (arm64), the main dashboard is empty and there are tons of errors on the log.

To Reproduce Steps to reproduce the behavior:

  1. Get some ARM device where you can run Yacht.
  2. Run Yacht on it. Watch the logs.
  3. Open the browser, login to Yatch, observe the empty dashboard.
  4. Observe lots of repeated errors on the log.

Expected behavior It should work out of the box. Sure, I understand on some platforms (arm) you can't get the memory stats, that's fine. But everything else should work fine, no exceptions (I mean, the Exception type that gets thrown).

Desktop (please complete the following information):

Additional context This issue was mentioned in #115 and was supposed to be fixed by f2c949b65f0dd89553c1559dbbaaebc0894827f9. However, it was broken by cb6eb568ac74370c8e619fea42b39ad7cff3fcf5 when it introduced the round(…) function around the mem_percent variable. The fix should be easy enough (a couple of lines) in backend/api/actions/apps.py.

Logs

yacht    | ERROR:    Exception in ASGI application
yacht    | Traceback (most recent call last):
yacht    |   File "/usr/lib/python3.8/site-packages/uvicorn/protocols/http/httptools_impl.py", line 390, in run_asgi
yacht    |     result = await app(self.scope, self.receive, self.send)
yacht    |   File "/usr/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
yacht    |     return await self.app(scope, receive, send)
yacht    |   File "/usr/lib/python3.8/site-packages/fastapi/applications.py", line 199, in __call__
yacht    |     await super().__call__(scope, receive, send)
yacht    |   File "/usr/lib/python3.8/site-packages/starlette/applications.py", line 111, in __call__
yacht    |     await self.middleware_stack(scope, receive, send)
yacht    |   File "/usr/lib/python3.8/site-packages/starlette/middleware/errors.py", line 181, in __call__
yacht    |     raise exc from None
yacht    |   File "/usr/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
yacht    |     await self.app(scope, receive, _send)
yacht    |   File "/usr/lib/python3.8/site-packages/starlette/exceptions.py", line 82, in __call__
yacht    |     raise exc from None
yacht    |   File "/usr/lib/python3.8/site-packages/starlette/exceptions.py", line 71, in __call__
yacht    |     await self.app(scope, receive, sender)
yacht    |   File "/usr/lib/python3.8/site-packages/starlette/routing.py", line 566, in __call__
yacht    |     await route.handle(scope, receive, send)
yacht    |   File "/usr/lib/python3.8/site-packages/starlette/routing.py", line 227, in handle
yacht    |     await self.app(scope, receive, send)
yacht    |   File "/usr/lib/python3.8/site-packages/starlette/routing.py", line 44, in app
yacht    |     await response(scope, receive, send)
yacht    |   File "/usr/lib/python3.8/site-packages/sse_starlette/sse.py", line 176, in __call__
yacht    |     await run_until_first_complete(
yacht    |   File "/usr/lib/python3.8/site-packages/starlette/concurrency.py", line 18, in run_until_first_complete
yacht    |     [task.result() for task in done]
yacht    |   File "/usr/lib/python3.8/site-packages/starlette/concurrency.py", line 18, in <listcomp>
yacht    |     [task.result() for task in done]
yacht    |   File "/usr/lib/python3.8/site-packages/sse_starlette/sse.py", line 199, in stream_response
yacht    |     async for data in self.body_iterator:
yacht    |   File "/./api/actions/apps.py", line 528, in all_stat_generator
yacht    |     async for event in merged:
yacht    |   File "/usr/lib/python3.8/site-packages/aiostream/stream/advanced.py", line 59, in base_combine
yacht    |     result = task.result()
yacht    |   File "/./api/actions/apps.py", line 503, in stat_generator
yacht    |     current_stats = await process_app_stats(line, app_name)
yacht    |   File "/./api/actions/apps.py", line 559, in process_app_stats
yacht    |     "mem_percent": round(mem_percent, 1),
yacht    | TypeError: type NoneType doesn't define __round__ method
denilsonsa commented 2 years ago

A simple fix would be to change these lines:

    mem_current = 0  # instead of None
    mem_total = 0  # instead of None
    mem_percent = 0  # instead of None

Or just move those assignments to a few lines above, outside the conditional. This allows us to get rid of this else.

However, it causes a side-effect: the UI will show a bunch of NaN and undefined in the memory stats. Thus, a "proper" fix would be to keep the Python code returning nulls, and update the Vue client-side code to handle null as not having data. This may require a longer change, so that the client-side UI looks intuitive.

Screenshot of the main dashboard

Also worth noting that the same NaN UI bug will happen at the apps stats page: https://github.com/SelfhostedPro/Yacht/blob/d0253afa27d85325b7c7f60e0ad1df16bf267b25/backend/api/utils/apps.py#L288-L316

Screenshot of the Stats sub-page inside the "app" page