From ede0b5b1a19c37547c19d875743e78b0278628d4 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Tue, 19 Sep 2023 09:43:18 -0500 Subject: vyos.utils: T5609: get disk device by partial id --- python/vyos/utils/disk.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 python/vyos/utils/disk.py (limited to 'python') diff --git a/python/vyos/utils/disk.py b/python/vyos/utils/disk.py new file mode 100644 index 000000000..ee540b107 --- /dev/null +++ b/python/vyos/utils/disk.py @@ -0,0 +1,23 @@ +# Copyright 2023 VyOS maintainers and contributors +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see . + +from pathlib import Path + +def device_from_id(id): + """ Return the device name from (partial) disk id """ + path = Path('/dev/disk/by-id') + for device in path.iterdir(): + if device.name.endswith(id): + return device.readlink().stem -- cgit v1.2.3 From 2d3f3297b575f88662495e14a7c7324ff73b6bfc Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Tue, 19 Sep 2023 21:36:55 -0500 Subject: op-mode: raid: T5608: define add/delete raid member --- op-mode-definitions/raid.xml.in | 69 +++++++++++++++++++++++++++++++++++++++ python/vyos/raid.py | 71 +++++++++++++++++++++++++++++++++++++++++ src/op_mode/raid.py | 44 +++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 op-mode-definitions/raid.xml.in create mode 100644 python/vyos/raid.py create mode 100755 src/op_mode/raid.py (limited to 'python') diff --git a/op-mode-definitions/raid.xml.in b/op-mode-definitions/raid.xml.in new file mode 100644 index 000000000..5d0c9ef3d --- /dev/null +++ b/op-mode-definitions/raid.xml.in @@ -0,0 +1,69 @@ + + + + + + + Add a RAID set element + + + + + + + + Add a member by disk id to a RAID set + + + + + Add a member to a RAID set + + sudo ${vyos_op_scripts_dir}/raid.py add --raid-set-name $3 --by-id --member $6 + + + + + + Add a member to a RAID set + + sudo ${vyos_op_scripts_dir}/raid.py add --raid-set-name $3 --member $5 + + + + + + + + + + Add a RAID set element + + + + + + + + Add a member by disk id to a RAID set + + + + + Add a member to a RAID set + + sudo ${vyos_op_scripts_dir}/raid.py delete --raid-set-name $3 --by-id --member $6 + + + + + + Add a member to a RAID set + + sudo ${vyos_op_scripts_dir}/raid.py delete --raid-set-name $3 --member $5 + + + + + + diff --git a/python/vyos/raid.py b/python/vyos/raid.py new file mode 100644 index 000000000..7fb794817 --- /dev/null +++ b/python/vyos/raid.py @@ -0,0 +1,71 @@ +# Copyright 2023 VyOS maintainers and contributors +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library. If not, see . + +from vyos.utils.disk import device_from_id +from vyos.utils.process import cmd + +def raid_sets(): + """ + Returns a list of RAID sets + """ + with open('/proc/mdstat') as f: + return [line.split()[0].rstrip(':') for line in f if line.startswith('md')] + +def raid_set_members(raid_set_name: str): + """ + Returns a list of members of a RAID set + """ + with open('/proc/mdstat') as f: + for line in f: + if line.startswith(raid_set_name): + return [l.split('[')[0] for l in line.split()[4:]] + return [] + +def partitions(): + """ + Returns a list of partitions + """ + with open('/proc/partitions') as f: + p = [l.strip().split()[-1] for l in list(f) if l.strip()] + p.remove('name') + return p + +def add_raid_member(raid_set_name: str, member: str, by_id: bool = False): + """ + Add a member to an existing RAID set + """ + if by_id: + member = device_from_id(member) + if raid_set_name not in raid_sets(): + raise ValueError(f"RAID set {raid_set_name} does not exist") + if member not in partitions(): + raise ValueError(f"Partition {member} does not exist") + if member in raid_set_members(raid_set_name): + raise ValueError(f"Partition {member} is already a member of RAID set {raid_set_name}") + cmd(f'mdadm --add /dev/{raid_set_name} /dev/{member}') + disk = cmd(f'lsblk -ndo PKNAME /dev/{member}') + cmd(f'grub-install /dev/{disk}') + +def delete_raid_member(raid_set_name: str, member: str, by_id: bool = False): + """ + Delete a member from an existing RAID set + """ + if by_id: + member = device_from_id(member) + if raid_set_name not in raid_sets(): + raise ValueError(f"RAID set {raid_set_name} does not exist") + if member not in raid_set_members(raid_set_name): + raise ValueError(f"Partition {member} is not a member of RAID set {raid_set_name}") + cmd(f'mdadm --remove /dev/{raid_set_name} /dev/{member}') diff --git a/src/op_mode/raid.py b/src/op_mode/raid.py new file mode 100755 index 000000000..fed8ae2c3 --- /dev/null +++ b/src/op_mode/raid.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# +import sys + +import vyos.opmode +from vyos.raid import add_raid_member +from vyos.raid import delete_raid_member + +def add(raid_set_name: str, member: str, by_id: bool = False): + try: + add_raid_member(raid_set_name, member, by_id) + except ValueError as e: + raise vyos.opmode.IncorrectValue(str(e)) + +def delete(raid_set_name: str, member: str, by_id: bool = False): + try: + delete_raid_member(raid_set_name, member, by_id) + except ValueError as e: + raise vyos.opmode.IncorrectValue(str(e)) + +if __name__ == '__main__': + try: + res = vyos.opmode.run(sys.modules[__name__]) + if res: + print(res) + except (ValueError, vyos.opmode.Error) as e: + print(e) + sys.exit(1) + -- cgit v1.2.3