summaryrefslogtreecommitdiff
path: root/ironic_python_agent/raid_utils.py
diff options
context:
space:
mode:
authorRiccardo Pittau <elfosardo@gmail.com>2021-02-10 13:48:29 +0100
committerRiccardo Pittau <elfosardo@gmail.com>2021-02-17 10:11:13 +0100
commit7d7940d90401df59258dc1963d51c7c53b3e3cf0 (patch)
tree131dad17ba5be5db2d1788d77bc3a302c6da2767 /ironic_python_agent/raid_utils.py
parenta35761c21fa8ad7856723b0ec68ddc87db39c709 (diff)
downloadironic-python-agent-7d7940d90401df59258dc1963d51c7c53b3e3cf0.tar.gz
Move some raid specific functions to raid_utils
To reduce size of the hardware module and separate the raid specific code in raid_utils, we move some functions and adapt the tests. Change-Id: I73f6cf118575b627e66727d88d5567377c1999a0
Diffstat (limited to 'ironic_python_agent/raid_utils.py')
-rw-r--r--ironic_python_agent/raid_utils.py87
1 files changed, 87 insertions, 0 deletions
diff --git a/ironic_python_agent/raid_utils.py b/ironic_python_agent/raid_utils.py
index d62b4280..962a6e9a 100644
--- a/ironic_python_agent/raid_utils.py
+++ b/ironic_python_agent/raid_utils.py
@@ -11,8 +11,10 @@
# limitations under the License.
import copy
+import re
from ironic_lib import utils as il_utils
+from oslo_concurrency import processutils
from oslo_log import log as logging
from ironic_python_agent import errors
@@ -26,6 +28,12 @@ LOG = logging.getLogger(__name__)
# https://www.rodsbooks.com/efi-bootloaders/principles.html
ESP_SIZE_MIB = 550
+# NOTE(rpittau) The partition number used to create a raid device.
+# Could be changed to variable if we ever decide, for example to create
+# some additional partitions (e.g. boot partitions), so md0 is on the
+# partition 1, md1 on the partition 2, and so on.
+RAID_PARTITION = 1
+
def get_block_devices_for_raid(block_devices, logical_disks):
"""Get block devices that are involved in the RAID configuration.
@@ -161,3 +169,82 @@ def create_raid_partition_tables(block_devices, partition_table_type,
parted_start_dict[dev_name] = calculate_raid_start(
target_boot_mode, partition_table_type, dev_name)
return parted_start_dict
+
+
+def _get_actual_component_devices(raid_device):
+ """Get the component devices of a Software RAID device.
+
+ Examine an md device and return its constituent devices.
+
+ :param raid_device: A Software RAID block device name.
+ :returns: A list of the component devices.
+ """
+ if not raid_device:
+ return []
+
+ try:
+ out, _ = utils.execute('mdadm', '--detail', raid_device,
+ use_standard_locale=True)
+ except processutils.ProcessExecutionError as e:
+ LOG.warning('Could not get component devices of %(dev)s: %(err)s',
+ {'dev': raid_device, 'err': e})
+ return []
+
+ component_devices = []
+ lines = out.splitlines()
+ # the first line contains the md device itself
+ for line in lines[1:]:
+ device = re.findall(r'/dev/\w+', line)
+ component_devices += device
+
+ return component_devices
+
+
+def create_raid_device(index, logical_disk):
+ """Create a raid device.
+
+ :param index: the index of the resulting md device.
+ :param logical_disk: the logical disk containing the devices used to
+ crete the raid.
+ :raise: errors.SoftwareRAIDError if not able to create the raid device
+ or fails to re-add a device to a raid.
+ """
+ md_device = '/dev/md%d' % index
+ component_devices = []
+ for device in logical_disk['block_devices']:
+ # The partition delimiter for all common harddrives (sd[a-z]+)
+ part_delimiter = ''
+ if 'nvme' in device:
+ part_delimiter = 'p'
+ component_devices.append(
+ device + part_delimiter + str(index + RAID_PARTITION))
+ raid_level = logical_disk['raid_level']
+ # The schema check allows '1+0', but mdadm knows it as '10'.
+ if raid_level == '1+0':
+ raid_level = '10'
+ try:
+ LOG.debug("Creating md device %(dev)s on %(comp)s",
+ {'dev': md_device, 'comp': component_devices})
+ utils.execute('mdadm', '--create', md_device, '--force',
+ '--run', '--metadata=1', '--level', raid_level,
+ '--raid-devices', len(component_devices),
+ *component_devices)
+ except processutils.ProcessExecutionError as e:
+ msg = "Failed to create md device {} on {}: {}".format(
+ md_device, ' '.join(component_devices), e)
+ raise errors.SoftwareRAIDError(msg)
+
+ # check for missing devices and re-add them
+ actual_components = _get_actual_component_devices(md_device)
+ missing = set(component_devices) - set(actual_components)
+ for dev in missing:
+ try:
+ LOG.warning('Found %(device)s to be missing from %(md)s '
+ '... re-adding!',
+ {'device': dev, 'md': md_device})
+ utils.execute('mdadm', '--add', md_device, dev,
+ attempts=3, delay_on_retry=True)
+ except processutils.ProcessExecutionError as e:
+ msg = "Failed re-add {} to {}: {}".format(
+ dev, md_device, e)
+ raise errors.SoftwareRAIDError(msg)