devices/lvm2.lv: add support for lvm devices files
LVM2 introduced system.devices as an alternative way to filter devices. Since we create devices in a stage the devices won't be added to the /etc/lvm/devices/system.devices file since /etc/ is inside the container. As a result the we can't see these devices and will fail with "Could not find parent device". Therefore we add support for managing our own per-service devices file, iff a `system.devices` is present.
This commit is contained in:
parent
99abc1373d
commit
090f768544
1 changed files with 49 additions and 6 deletions
|
|
@ -58,13 +58,45 @@ class LVService(devices.DeviceService):
|
|||
super().__init__(args)
|
||||
self.fullname = None
|
||||
self.target = None
|
||||
self.devices_file = None
|
||||
|
||||
@staticmethod
|
||||
def lv_set_active(fullname: str, status: bool):
|
||||
def manage_devices_file(self, device: str):
|
||||
# if LVM2 uses system.devices file, the LVM2 physical device we created
|
||||
# inside the stage won't be seen since it wont be added to `system.devices`
|
||||
# so we need to manage our own devices file
|
||||
|
||||
if not os.path.exists("/etc/lvm/devices/system.devices"):
|
||||
return
|
||||
|
||||
self.devices_file = f"osbuild-{os.getpid()}.devices"
|
||||
print(f"adding device to '{self.devices_file}'")
|
||||
|
||||
cmd = [
|
||||
"lvmdevices",
|
||||
"--adddev", device,
|
||||
"--devicesfile", self.devices_file
|
||||
]
|
||||
|
||||
res = subprocess.run(cmd,
|
||||
check=False,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.PIPE,
|
||||
encoding="UTF-8")
|
||||
|
||||
if res.returncode != 0:
|
||||
data = res.stderr.strip()
|
||||
msg = f"Failed to add '{device}' to '{self.devices_file}': {data}"
|
||||
raise RuntimeError(msg)
|
||||
|
||||
def lv_set_active(self, fullname: str, status: bool):
|
||||
mode = "y" if status else "n"
|
||||
cmd = [
|
||||
"lvchange", "--activate", mode, fullname
|
||||
]
|
||||
|
||||
if self.devices_file:
|
||||
cmd += ["--devicesfile", self.devices_file]
|
||||
|
||||
res = subprocess.run(cmd,
|
||||
check=False,
|
||||
stdout=subprocess.DEVNULL,
|
||||
|
|
@ -76,8 +108,7 @@ class LVService(devices.DeviceService):
|
|||
msg = f"Failed to set LV device ({fullname}) status: {data}"
|
||||
raise RuntimeError(msg)
|
||||
|
||||
@staticmethod
|
||||
def volume_group_for_device(device: str) -> str:
|
||||
def volume_group_for_device(self, device: str) -> str:
|
||||
# Find the volume group that belongs to the device specified via `parent`
|
||||
vg_name = None
|
||||
count = 0
|
||||
|
|
@ -86,6 +117,9 @@ class LVService(devices.DeviceService):
|
|||
"pvdisplay", "-C", "--noheadings", "-o", "vg_name", device
|
||||
]
|
||||
|
||||
if self.devices_file:
|
||||
cmd += ["--devicesfile", self.devices_file]
|
||||
|
||||
while True:
|
||||
res = subprocess.run(cmd,
|
||||
check=False,
|
||||
|
|
@ -110,8 +144,7 @@ class LVService(devices.DeviceService):
|
|||
|
||||
return vg_name
|
||||
|
||||
@staticmethod
|
||||
def device_for_logical_volume(vg_name: str, volume: str) -> Tuple[int, int]:
|
||||
def device_for_logical_volume(self, vg_name: str, volume: str) -> Tuple[int, int]:
|
||||
# Now that we have the volume group, find the specified logical volume and its device path
|
||||
|
||||
cmd = [
|
||||
|
|
@ -122,6 +155,9 @@ class LVService(devices.DeviceService):
|
|||
vg_name
|
||||
]
|
||||
|
||||
if self.devices_file:
|
||||
cmd += ["--devicesfile", self.devices_file]
|
||||
|
||||
res = subprocess.run(cmd,
|
||||
check=False,
|
||||
stdout=subprocess.PIPE,
|
||||
|
|
@ -144,6 +180,9 @@ class LVService(devices.DeviceService):
|
|||
assert not parent.startswith("/")
|
||||
parent_path = os.path.join("/dev", parent)
|
||||
|
||||
# Add the device to a lvm devices file on supported systems
|
||||
self.manage_devices_file(parent_path)
|
||||
|
||||
# Find the volume group that belongs to the device specified
|
||||
# via `parent`
|
||||
vg = self.volume_group_for_device(parent_path)
|
||||
|
|
@ -181,6 +220,10 @@ class LVService(devices.DeviceService):
|
|||
self.lv_set_active(self.fullname, False)
|
||||
self.fullname = None
|
||||
|
||||
if self.devices_file:
|
||||
os.unlink(os.path.join("/etc/lvm/devices", self.devices_file))
|
||||
self.devices_file = None
|
||||
|
||||
|
||||
def main():
|
||||
service = LVService.from_args(sys.argv[1:])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue