Commit fd1f7013 authored by Dean Birch's avatar Dean Birch Committed by Neil Williams

Pass USB devices to LXC via ID_FS_LABEL

If a disk device fails to set a unique serial, but does allow a customisable
filesystem label, then this method allows the device to be passed to
LXC.

Change-Id: I1b1474ea16df3aef0ed8b48e9af497393611a485
parent a0104eb9
......@@ -35,6 +35,7 @@ from lava_dispatcher.connections.lxc import (
from lava_dispatcher.shell import ExpectShellSession
from lava_dispatcher.utils.shell import infrastructure_error
from lava_dispatcher.utils.udev import get_udev_devices
from lava_dispatcher.utils.udev import allow_fs_label
class BootLxc(Boot):
......@@ -104,7 +105,8 @@ class LxcAddStaticDevices(Action):
"""
usb_devices = []
for device in self.job.device.get('static_info', []):
if 'board_id' in device:
if 'board_id' in device \
or 'fs_label' in device:
# This is a USB device
usb_devices.append(device)
return usb_devices
......@@ -112,9 +114,14 @@ class LxcAddStaticDevices(Action):
def validate(self):
super(LxcAddStaticDevices, self).validate()
# If there are no USB devices under static_info then this action should be idempotent.
# If we are allowed to use a filesystem label, we don't require a board_id
# By default, we do require a board_id (serial)
requires_board_id = not allow_fs_label(self.job.device)
try:
for usb_device in self.get_usb_devices():
if usb_device.get('board_id', '') in ['', '0000000000']:
if usb_device.get('board_id', '') in ['', '0000000000'] and \
requires_board_id:
self.errors = "board_id unset"
if usb_device.get('usb_vendor_id', '') == '0000':
self.errors = 'usb_vendor_id unset'
......
......@@ -43,6 +43,7 @@ from lava_dispatcher.utils.constants import (
UDEV_RULES_DIR,
)
from lava_dispatcher.utils.udev import lxc_udev_rule
from lava_dispatcher.utils.udev import allow_fs_label
from lava_dispatcher.utils.filesystem import (
debian_package_version,
lxc_path,
......@@ -233,10 +234,14 @@ class LxcCreateUdevRuleAction(DeployAction):
if 'device_info' in self.job.device \
and not isinstance(self.job.device.get('device_info'), list):
self.errors = "device_info unset"
# If we are allowed to use a filesystem label, we don't require a board_id
# By default, we do require a board_id (serial)
requires_board_id = not allow_fs_label(self.job.device)
try:
if 'device_info' in self.job.device:
for usb_device in self.job.device['device_info']:
if usb_device.get('board_id', '') in ['', '0000000000']:
if usb_device.get('board_id', '') in ['', '0000000000'] \
and requires_board_id:
self.errors = "board_id unset"
if usb_device.get('usb_vendor_id', '') == '0000':
self.errors = 'usb_vendor_id unset'
......@@ -282,6 +287,7 @@ class LxcCreateUdevRuleAction(DeployAction):
data = {'serial_number': str(device.get('board_id', '')),
'vendor_id': device.get('usb_vendor_id', None),
'product_id': device.get('usb_product_id', None),
'fs_label': device.get('fs_label', None),
'lxc_name': lxc_name,
'device_info_file': device_info_file,
'logging_url': logging_url,
......
......@@ -218,6 +218,7 @@ def get_udev_devices(job=None, logger=None, device_info=None):
board_id = str(usb_device.get('board_id', ''))
usb_vendor_id = str(usb_device.get('usb_vendor_id', ''))
usb_product_id = str(usb_device.get('usb_product_id', ''))
usb_fs_label = str(usb_device.get('fs_label', ''))
# check if device is already connected
# try with all parameters such as board id, usb_vendor_id and
# usb_product_id
......@@ -251,6 +252,15 @@ def get_udev_devices(job=None, logger=None, device_info=None):
device_paths.add(child.device_node)
for link in device.device_links:
device_paths.add(link)
elif usb_fs_label:
# Just restrict by filesystem label.
if device.get('ID_FS_LABEL') == usb_fs_label:
device_paths.add(device.device_node)
for child in device.children:
if child.device_node:
device_paths.add(child.device_node)
for link in device.device_links:
device_paths.add(link)
if logger and device_paths:
logger.debug("Adding %s", ', '.join(device_paths))
return list(device_paths)
......@@ -264,6 +274,7 @@ def usb_device_wait(job, device_actions=None):
board_id = str(usb_device.get('board_id', ''))
usb_vendor_id = str(usb_device.get('usb_vendor_id', ''))
usb_product_id = str(usb_device.get('usb_product_id', ''))
usb_fs_label = str(usb_device.get('fs_label', ''))
# monitor for device
monitor = pyudev.Monitor.from_netlink(context)
if board_id and usb_vendor_id and usb_product_id:
......@@ -287,16 +298,42 @@ def usb_device_wait(job, device_actions=None):
and device.action in device_actions:
break
return
elif usb_fs_label:
for device in iter(monitor.poll, None):
if (device.get('ID_FS_LABEL') == usb_fs_label) \
and device.action in device_actions:
break
return
def allow_fs_label(device):
# boot/deploy methods that indicate that the device in question
# will require a filesystem label to identify a device.
# So far, mps devices are supported, but these don't provide a
# unique serial, so fs label must be used.
fs_label_methods = ['mps']
# Don't allow using filesystem labels by default as they are
# unreliable, and can be changed via a malicious job.
_allow_fs_label = False
for method in fs_label_methods:
if method in device['actions']['boot']['methods'] \
or method in device['actions']['deploy']['methods']:
_allow_fs_label = True
return _allow_fs_label
def lxc_udev_rule(data):
"""Construct the udev rule string."""
rule = 'ACTION=="add", '
rule += 'ATTR{{serial}}=="{serial_number}", '
if data['serial_number']:
rule += 'ATTR{{serial}}=="{serial_number}", '
if data["vendor_id"] is not None:
rule += 'ATTR{{idVendor}}=="{vendor_id}", '
if data["product_id"] is not None:
rule += 'ATTR{{idProduct}}=="{product_id}", '
if data["fs_label"] is not None:
rule += 'ENV{{ID_FS_LABEL}}=="{fs_label}", '
rule += 'RUN+="/usr/share/lava-dispatcher/lava_lxc_device_add.py ' \
'--lxc-name {lxc_name} --device-node $name ' \
'--job-id {job_id}'
......@@ -310,5 +347,7 @@ def lxc_udev_rule(data):
rule += " --slave-cert %s" % data["slave_cert"]
if data["ipv6"]:
rule += " --ipv6"
if data["fs_label"] is not None:
rule = 'IMPORT{builtin}="blkid"\n' + rule
rule += '"\n'
return rule
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment