Skip to content

Commit 3371b1d

Browse files
authored
Merge branch 'main' into dutlink-test-fix
2 parents 82981eb + ee4720b commit 3371b1d

File tree

21 files changed

+261
-222
lines changed

21 files changed

+261
-222
lines changed
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
import logging
21
from dataclasses import dataclass
32

43
from jumpstarter.driver import Driver, export
54

6-
logger = logging.getLogger(__name__)
7-
85
@dataclass(kw_only=True)
96
class ${DRIVER_CLASS}(Driver):
107
"""${DRIVE_NAME} driver for Jumpstarter"""
@@ -13,7 +10,8 @@ class ${DRIVER_CLASS}(Driver):
1310
some_other_config: int = 69
1411

1512
def __post_init__(self):
16-
super().__post_init__()
13+
if hasattr(super(), "__post_init__"):
14+
super().__post_init__()
1715
# some initialization here.
1816

1917
@classmethod
@@ -22,10 +20,10 @@ class ${DRIVER_CLASS}(Driver):
2220

2321
@export
2422
def method1(self):
25-
logger.info("Method1 called")
23+
self.logger.info("Method1 called")
2624
return "method1 response"
2725

2826
@export
2927
def method2(self):
30-
logger.info("Method2 called")
28+
self.logger.info("Method2 called")
3129
return "method2 response"

packages/jumpstarter-driver-can/jumpstarter_driver_can/client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,13 @@ class CanClient(DriverClient, can.BusABC):
3333
"""
3434

3535
def __post_init__(self):
36+
if hasattr(super(), "__post_init__"):
37+
super().__post_init__()
38+
3639
self._periodic_tasks: List[_SelfRemovingCyclicTask] = []
3740
self._filters = None
3841
self._is_shutdown: bool = False
3942

40-
super().__post_init__()
41-
4243
@property
4344
@validate_call(validate_return=True)
4445
def state(self) -> can.BusState:

packages/jumpstarter-driver-can/jumpstarter_driver_can/driver.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ def client(cls) -> str:
4545
return "jumpstarter_driver_can.client.CanClient"
4646

4747
def __post_init__(self):
48-
super().__post_init__()
48+
if hasattr(super(), "__post_init__"):
49+
super().__post_init__()
50+
4951
self.bus = can.Bus(channel=self.channel, interface=self.interface)
5052

5153
@export
@@ -195,7 +197,9 @@ def client(cls) -> str:
195197
return "jumpstarter_driver_can.client.IsoTpClient"
196198

197199
def __post_init__(self):
198-
super().__post_init__()
200+
if hasattr(super(), "__post_init__"):
201+
super().__post_init__()
202+
199203
self.bus = can.Bus(channel=self.channel, interface=self.interface)
200204
self.notifier = can.Notifier(self.bus, [])
201205
self.stack = isotp.NotifierBasedCanStack(

packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/driver.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22

3-
import logging
43
import os
54
import time
65
from collections.abc import AsyncGenerator
@@ -19,8 +18,6 @@
1918

2019
from jumpstarter.driver import Driver, export
2120

22-
log = logging.getLogger(__name__)
23-
2421

2522
@dataclass(kw_only=True)
2623
class DutlinkConfig:
@@ -32,10 +29,13 @@ class DutlinkConfig:
3229
tty: str | None = field(init=False, default=None)
3330

3431
def __post_init__(self):
32+
if hasattr(super(), "__post_init__"):
33+
super().__post_init__()
34+
3535
for dev in usb.core.find(idVendor=0x2B23, idProduct=0x1012, find_all=True):
3636
serial = usb.util.get_string(dev, dev.iSerialNumber)
3737
if serial == self.serial or self.serial is None:
38-
log.debug(f"found dutlink board with serial {serial}")
38+
self.logger.debug(f"found dutlink board with serial {serial}")
3939

4040
self.serial = serial
4141
self.dev = dev
@@ -78,30 +78,30 @@ def control(self, direction, ty, actions, action, value):
7878

7979
if direction == usb.ENDPOINT_IN:
8080
str_value = bytes(res).decode("utf-8")
81-
log.debug(
82-
"ctrl_transfer result: %s",
83-
)
81+
self.logger.debug("ctrl_transfer result: %s", str_value)
8482
return str_value
8583

8684

8785
@dataclass(kw_only=True)
88-
class DutlinkSerial(DutlinkConfig, PySerial):
89-
url: str | None = field(init=False, default=None)
90-
86+
class DutlinkSerialConfig(DutlinkConfig, Driver):
9187
def __post_init__(self):
92-
super().__post_init__()
88+
if hasattr(super(), "__post_init__"):
89+
super().__post_init__()
9390

9491
self.url = self.tty
9592

96-
super(PySerial, self).__post_init__()
93+
94+
@dataclass(kw_only=True)
95+
class DutlinkSerial(PySerial, DutlinkSerialConfig):
96+
url: str | None = field(init=False, default=None)
9797

9898

9999
@dataclass(kw_only=True)
100100
class DutlinkPower(DutlinkConfig, PowerInterface, Driver):
101101
last_action: str | None = field(default=None)
102102

103103
def control(self, action):
104-
log.debug(f"power control: {action}")
104+
self.logger.debug(f"power control: {action}")
105105
if self.last_action == action:
106106
return
107107

@@ -160,7 +160,7 @@ class DutlinkStorageMux(DutlinkConfig, StorageMuxInterface, Driver):
160160
storage_device: str
161161

162162
def control(self, action):
163-
log.debug(f"storage control: {action}")
163+
self.logger.debug(f"storage control: {action}")
164164
return super().control(
165165
usb.ENDPOINT_OUT,
166166
0x02,
@@ -190,9 +190,9 @@ def off(self):
190190
async def wait_for_storage_device(self):
191191
with fail_after(20):
192192
while True:
193-
log.debug(f"waiting for storage device {self.storage_device}")
193+
self.logger.debug(f"waiting for storage device {self.storage_device}")
194194
if os.path.exists(self.storage_device):
195-
log.debug(f"storage device {self.storage_device} is ready")
195+
self.logger.debug(f"storage device {self.storage_device} is ready")
196196
# https://stackoverflow.com/a/2774125
197197
fd = os.open(self.storage_device, os.O_WRONLY)
198198
try:
@@ -213,7 +213,7 @@ async def write(self, src: str):
213213
async for chunk in res:
214214
await stream.send(chunk)
215215
if total_bytes > next_print:
216-
log.debug(f"{self.storage_device} written {total_bytes / (1024 * 1024)} MB")
216+
self.logger.debug(f"{self.storage_device} written {total_bytes / (1024 * 1024)} MB")
217217
next_print += 50 * 1024 * 1024
218218
total_bytes += len(chunk)
219219

@@ -252,18 +252,20 @@ class Dutlink(DutlinkConfig, CompositeInterface, Driver):
252252
"""
253253

254254
def __post_init__(self):
255-
super().__post_init__()
255+
if hasattr(super(), "__post_init__"):
256+
super().__post_init__()
256257

257258
self.children["power"] = DutlinkPower(serial=self.serial, timeout_s=self.timeout_s)
258-
self.children["storage"] = DutlinkStorageMux(serial=self.serial, storage_device=self.storage_device,
259-
timeout_s=self.timeout_s)
259+
self.children["storage"] = DutlinkStorageMux(
260+
serial=self.serial, storage_device=self.storage_device, timeout_s=self.timeout_s
261+
)
260262

261263
# if an alternate serial port has been requested, use it
262264
if self.alternate_console is not None:
263265
try:
264266
self.children["console"] = PySerial(url=self.alternate_console, baudrate=self.baudrate)
265267
except SerialException:
266-
log.info(
268+
self.logger.info(
267269
f"failed to open alternate console {self.alternate_console} but trying to power on the target once"
268270
)
269271
self.children["power"].on()

packages/jumpstarter-driver-http/jumpstarter_driver_http/driver.py

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import logging
21
import os
32
from dataclasses import dataclass, field
43
from pathlib import Path
@@ -10,8 +9,6 @@
109

1110
from jumpstarter.driver import Driver, export
1211

13-
logger = logging.getLogger(__name__)
14-
1512

1613
class HttpServerError(Exception):
1714
"""Base exception for HTTP server errors"""
@@ -21,38 +18,39 @@ class FileWriteError(HttpServerError):
2118
"""Exception raised when file writing fails"""
2219

2320

24-
def get_default_ip():
25-
try:
26-
import socket
27-
28-
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
29-
s.connect(("8.8.8.8", 80))
30-
ip = s.getsockname()[0]
31-
s.close()
32-
return ip
33-
except Exception:
34-
logger.warning("Could not determine default IP address, falling back to 0.0.0.0")
35-
return "0.0.0.0"
36-
37-
3821
@dataclass(kw_only=True)
3922
class HttpServer(Driver):
4023
"""HTTP Server driver for Jumpstarter"""
4124

4225
root_dir: str = "/var/www"
43-
host: str = field(default_factory=get_default_ip)
26+
host: str = field(default=None)
4427
port: int = 8080
4528
app: web.Application = field(init=False, default_factory=web.Application)
4629
runner: Optional[web.AppRunner] = field(init=False, default=None)
4730

4831
def __post_init__(self):
49-
super().__post_init__()
32+
if hasattr(super(), "__post_init__"):
33+
super().__post_init__()
34+
5035
os.makedirs(self.root_dir, exist_ok=True)
5136
self.app.router.add_routes(
5237
[
5338
web.get("/{filename}", self.get_file),
5439
]
5540
)
41+
if self.host is None:
42+
self.host = self.get_default_ip()
43+
44+
def get_default_ip(self):
45+
try:
46+
import socket
47+
48+
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
49+
s.connect(("8.8.8.8", 80))
50+
return s.getsockname()[0]
51+
except Exception:
52+
self.logger.warning("Could not determine default IP address, falling back to 0.0.0.0")
53+
return "0.0.0.0"
5654

5755
@classmethod
5856
def client(cls) -> str:
@@ -86,11 +84,11 @@ async def put_file(self, filename: str, src_stream) -> str:
8684
async for chunk in src:
8785
await dst.send(chunk)
8886

89-
logger.info(f"File '{filename}' written to '{file_path}'")
87+
self.logger.info(f"File '{filename}' written to '{file_path}'")
9088
return f"{self.get_url()}/{filename}"
9189

9290
except Exception as e:
93-
logger.error(f"Failed to upload file '{filename}': {e}")
91+
self.logger.error(f"Failed to upload file '{filename}': {e}")
9492
raise FileWriteError(f"Failed to upload file '{filename}': {e}") from e
9593

9694
@export
@@ -112,10 +110,10 @@ async def delete_file(self, filename: str) -> str:
112110
raise HttpServerError(f"File '{filename}' does not exist.")
113111
try:
114112
file_path.unlink()
115-
logger.info(f"File '{filename}' has been deleted.")
113+
self.logger.info(f"File '{filename}' has been deleted.")
116114
return filename
117115
except Exception as e:
118-
logger.error(f"Failed to delete file '{filename}': {e}")
116+
self.logger.error(f"Failed to delete file '{filename}': {e}")
119117
raise HttpServerError(f"Failed to delete file '{filename}': {e}") from e
120118

121119
async def get_file(self, request) -> web.FileResponse:
@@ -134,9 +132,9 @@ async def get_file(self, request) -> web.FileResponse:
134132
filename = request.match_info["filename"]
135133
file_path = os.path.join(self.root_dir, filename)
136134
if not os.path.isfile(file_path):
137-
logger.warning(f"File not found: {file_path}")
135+
self.logger.warning(f"File not found: {file_path}")
138136
raise web.HTTPNotFound(text=f"File '{filename}' not found.")
139-
logger.info(f"Serving file: {file_path}")
137+
self.logger.info(f"Serving file: {file_path}")
140138
return web.FileResponse(file_path)
141139

142140
@export
@@ -155,7 +153,7 @@ def list_files(self) -> list[str]:
155153
files = [f for f in files if os.path.isfile(os.path.join(self.root_dir, f))]
156154
return files
157155
except Exception as e:
158-
logger.error(f"Failed to list files: {e}")
156+
self.logger.error(f"Failed to list files: {e}")
159157
raise HttpServerError(f"Failed to list files: {e}") from e
160158

161159
@export
@@ -167,7 +165,7 @@ async def start(self):
167165
HttpServerError: If the server fails to start.
168166
"""
169167
if self.runner is not None:
170-
logger.warning("HTTP server is already running.")
168+
self.logger.warning("HTTP server is already running.")
171169
return
172170

173171
self.runner = web.AppRunner(self.app)
@@ -176,7 +174,7 @@ async def start(self):
176174

177175
site = web.TCPSite(self.runner, self.host, self.port)
178176
await site.start()
179-
logger.info(f"HTTP server started at http://{self.host}:{self.port}")
177+
self.logger.info(f"HTTP server started at http://{self.host}:{self.port}")
180178

181179
@export
182180
async def stop(self):
@@ -187,11 +185,11 @@ async def stop(self):
187185
HttpServerError: If the server fails to stop.
188186
"""
189187
if self.runner is None:
190-
logger.warning("HTTP server is not running.")
188+
self.logger.warning("HTTP server is not running.")
191189
return
192190

193191
await self.runner.cleanup()
194-
logger.info("HTTP server stopped.")
192+
self.logger.info("HTTP server stopped.")
195193
self.runner = None
196194

197195
@export
@@ -230,7 +228,7 @@ def close(self):
230228
if anyio.get_current_task():
231229
anyio.from_thread.run(self._async_cleanup)
232230
except Exception as e:
233-
logger.warning(f"HTTP server cleanup failed synchronously: {e}")
231+
self.logger.warning(f"HTTP server cleanup failed synchronously: {e}")
234232
self.runner = None
235233
super().close()
236234

@@ -239,6 +237,6 @@ async def _async_cleanup(self):
239237
if self.runner:
240238
await self.runner.shutdown()
241239
await self.runner.cleanup()
242-
logger.info("HTTP server cleanup completed asynchronously.")
240+
self.logger.info("HTTP server cleanup completed asynchronously.")
243241
except Exception as e:
244-
logger.error(f"HTTP server cleanup failed asynchronously: {e}")
242+
self.logger.error(f"HTTP server cleanup failed asynchronously: {e}")

0 commit comments

Comments
 (0)