devices: introduce new device manager class

Introduce a new class to manage devices, `DeviceManger` and move the
code to open devices from the `Device` here. The main insight of why
the logic should be place here is that certain information is needed
to open the devices, independently of specific type: the path to the
device node directory, `devpath`, the actual `tree` and the service
manager instance to start the actual service. Instead of passing all
this information again and again to the `Device` class, we now have
a specialized (service) manager class for devices that has all the
needed information all the time. Additionally, the special handling
of parent devices is moved from the pipeline to the service manager,
which is where it belongs.
This will make even more sense for mounts, where the `DeviceManger`
can then be passed to access the individual devices.
Port the test to use the `DeviceManager`.
This commit is contained in:
Christian Kellner 2021-10-18 15:50:30 +02:00 committed by Tom Gundersen
parent 94d8fb1ff7
commit a5e07cf506
3 changed files with 33 additions and 13 deletions

View file

@ -44,21 +44,43 @@ class Device:
m.update(json.dumps(self.options, sort_keys=True).encode())
return m.hexdigest()
def open(self, mgr: host.ServiceManager, dev: str, parent: str, tree: str) -> Dict:
class DeviceManager:
"""Manager for Devices
Uses a `host.ServiceManager` to open `Device` instances.
"""
def __init__(self, mgr: host.ServiceManager, devpath: str, tree: str) -> Dict:
self.service_manager = mgr
self.devpath = devpath
self.tree = tree
self.devices = {}
def open(self, dev: Device) -> Dict:
if dev.parent:
parent = self.devices[dev.parent.name]["path"]
else:
parent = None
args = {
# global options
"dev": dev,
"tree": tree,
"dev": self.devpath,
"tree": self.tree,
"parent": parent,
# per device options
"options": self.options,
"options": dev.options,
}
client = mgr.start(f"device/{self.name}", self.info.path)
mgr = self.service_manager
client = mgr.start(f"device/{dev.name}", dev.info.path)
res = client.call("open", args)
self.devices[dev.name] = res
return res

View file

@ -10,7 +10,7 @@ from . import buildroot
from . import host
from . import objectstore
from . import remoteloop
from .devices import Device
from .devices import Device, DeviceManager
from .inputs import Input
from .mounts import Mount
from .sources import Source
@ -164,12 +164,9 @@ class Stage:
data = ip.map(mgr, storeapi, inputs_tmpdir)
inputs[key] = data
for key, dev in self.devices.items():
parent = None
if dev.parent:
parent = devices[dev.parent.name]["path"]
reply = dev.open(mgr, build_root.dev, parent, tree)
devices[key] = reply
devmgr = DeviceManager(mgr, build_root.dev, tree)
for name, dev in self.devices.items():
devices[name] = devmgr.open(dev)
for key, mount in self.mounts.items():
relpath = devices[mount.device.name]["path"]

View file

@ -48,7 +48,8 @@ def test_loopback_basic(tmpdir):
dev = devices.Device("loop", info, None, options)
with host.ServiceManager() as mgr:
reply = dev.open(mgr, devpath, None, tree)
devmgr = devices.DeviceManager(mgr, devpath, tree)
reply = devmgr.open(dev)
assert reply
assert reply["path"]