Blame tests/mdraid_test.py

Packit 2ba279
import unittest
Packit 2ba279
import os
Packit 2ba279
import re
Packit 2ba279
import time
Packit 2ba279
from contextlib import contextmanager
Packit 2ba279
import overrides_hack
Packit 2ba279
import six
Packit 2ba279
Packit 2ba279
from utils import create_sparse_tempfile, create_lio_device, delete_lio_device, fake_utils, fake_path, TestTags, tag_test
Packit 2ba279
from gi.repository import BlockDev, GLib
Packit 2ba279
Packit 2ba279
Packit 2ba279
@contextmanager
Packit 2ba279
def wait_for_action(action_name):
Packit 2ba279
    try:
Packit 2ba279
        yield
Packit 2ba279
    finally:
Packit 2ba279
        time.sleep(2)
Packit 2ba279
        action = True
Packit 2ba279
        while action:
Packit 2ba279
            with open("/proc/mdstat", "r") as f:
Packit 2ba279
                action = action_name in f.read()
Packit 2ba279
            if action:
Packit 2ba279
                print("Sleeping")
Packit 2ba279
                time.sleep(1)
Packit 2ba279
Packit 2ba279
class MDTest(unittest.TestCase):
Packit 2ba279
Packit 2ba279
    requested_plugins = BlockDev.plugin_specs_from_names(("mdraid",))
Packit 2ba279
Packit 2ba279
    @classmethod
Packit 2ba279
    def setUpClass(cls):
Packit 2ba279
        if not BlockDev.is_initialized():
Packit 2ba279
            BlockDev.init(cls.requested_plugins, None)
Packit 2ba279
        else:
Packit 2ba279
            BlockDev.reinit(cls.requested_plugins, True, None)
Packit 2ba279
Packit 2ba279
class MDNoDevTestCase(MDTest):
Packit 2ba279
Packit 2ba279
    requested_plugins = BlockDev.plugin_specs_from_names(("mdraid",))
Packit 2ba279
Packit 2ba279
    @classmethod
Packit 2ba279
    def setUpClass(cls):
Packit 2ba279
        if not BlockDev.is_initialized():
Packit 2ba279
            BlockDev.init(cls.requested_plugins, None)
Packit 2ba279
        else:
Packit 2ba279
            BlockDev.reinit(cls.requested_plugins, True, None)
Packit 2ba279
Packit 2ba279
    @tag_test(TestTags.NOSTORAGE)
Packit 2ba279
    def test_get_superblock_size(self):
Packit 2ba279
        """Verify that superblock size si calculated properly"""
Packit 2ba279
Packit 2ba279
        # 2 MiB for versions <= 1.0
Packit 2ba279
        self.assertEqual(BlockDev.md_get_superblock_size(2 * 1024**3, "0.9"), 2 * 1024**2)
Packit 2ba279
        self.assertEqual(BlockDev.md_get_superblock_size(2 * 1024**3, "1.0"), 2 * 1024**2)
Packit 2ba279
Packit 2ba279
        # no version, "default" or > 1.0
Packit 2ba279
        self.assertEqual(BlockDev.md_get_superblock_size(256 * 1024**3, None), 128 * 1024**2)
Packit 2ba279
        self.assertEqual(BlockDev.md_get_superblock_size(128 * 1024**3, None), 128 * 1024**2)
Packit 2ba279
        self.assertEqual(BlockDev.md_get_superblock_size(64 * 1024**3, "default"), 64 * 1024**2)
Packit 2ba279
        self.assertEqual(BlockDev.md_get_superblock_size(63 * 1024**3, "default"), 32 * 1024**2)
Packit 2ba279
        self.assertEqual(BlockDev.md_get_superblock_size(10 * 1024**3, "1.1"), 8 * 1024**2)
Packit 2ba279
        self.assertEqual(BlockDev.md_get_superblock_size(1 * 1024**3, "1.1"), 1 * 1024**2)
Packit 2ba279
        self.assertEqual(BlockDev.md_get_superblock_size(1023 * 1024**2, "1.2"), 1 * 1024**2)
Packit 2ba279
        self.assertEqual(BlockDev.md_get_superblock_size(512 * 1024**2, "1.2"), 1 * 1024**2)
Packit 2ba279
Packit 2ba279
        # unsupported version -> default superblock size
Packit 2ba279
        self.assertEqual(BlockDev.md_get_superblock_size(257 * 1024**2, version="unknown version"),
Packit 2ba279
                         2 * 1024**2)
Packit 2ba279
Packit 2ba279
    @tag_test(TestTags.NOSTORAGE)
Packit 2ba279
    def test_canonicalize_uuid(self):
Packit 2ba279
        """Verify that UUID canonicalization works as expected"""
Packit 2ba279
Packit 2ba279
        self.assertEqual(BlockDev.md_canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236"),
Packit 2ba279
                         "3386ff85-f501-2621-4a43-5f061eb47236")
Packit 2ba279
Packit 2ba279
        with six.assertRaisesRegex(self, GLib.GError, r'malformed or invalid'):
Packit 2ba279
            BlockDev.md_canonicalize_uuid("malformed-uuid-example")
Packit 2ba279
Packit 2ba279
    @tag_test(TestTags.NOSTORAGE)
Packit 2ba279
    def test_get_md_uuid(self):
Packit 2ba279
        """Verify that getting UUID in MD RAID format works as expected"""
Packit 2ba279
Packit 2ba279
        self.assertEqual(BlockDev.md_get_md_uuid("3386ff85-f501-2621-4a43-5f061eb47236"),
Packit 2ba279
                         "3386ff85:f5012621:4a435f06:1eb47236")
Packit 2ba279
Packit 2ba279
        with six.assertRaisesRegex(self, GLib.GError, r'malformed or invalid'):
Packit 2ba279
            BlockDev.md_get_md_uuid("malformed-uuid-example")
Packit 2ba279
Packit 2ba279
class MDTestCase(MDTest):
Packit 2ba279
Packit 2ba279
    def setUp(self):
Packit 2ba279
        if os.uname()[-1] == "i686":
Packit 2ba279
            self.skipTest("Skipping hanging MD RAID tests on i686")
Packit 2ba279
Packit 2ba279
        self.addCleanup(self._clean_up)
Packit 2ba279
        self.dev_file = create_sparse_tempfile("md_test", 10 * 1024**2)
Packit 2ba279
        self.dev_file2 = create_sparse_tempfile("md_test", 10 * 1024**2)
Packit 2ba279
        self.dev_file3 = create_sparse_tempfile("md_test", 10 * 1024**2)
Packit 2ba279
Packit 2ba279
        try:
Packit 2ba279
            self.loop_dev = create_lio_device(self.dev_file)
Packit 2ba279
        except RuntimeError as e:
Packit 2ba279
            raise RuntimeError("Failed to setup loop device for testing: %s" % e)
Packit 2ba279
        try:
Packit 2ba279
            self.loop_dev2 = create_lio_device(self.dev_file2)
Packit 2ba279
        except RuntimeError as e:
Packit 2ba279
            raise RuntimeError("Failed to setup loop device for testing: %s" % e)
Packit 2ba279
        try:
Packit 2ba279
            self.loop_dev3 = create_lio_device(self.dev_file3)
Packit 2ba279
        except RuntimeError as e:
Packit 2ba279
            raise RuntimeError("Failed to setup loop device for testing: %s" % e)
Packit 2ba279
Packit 2ba279
    def _clean_up(self):
Packit 2ba279
        try:
Packit 2ba279
            BlockDev.md_deactivate("bd_test_md")
Packit 2ba279
        except:
Packit 2ba279
            pass
Packit 2ba279
        try:
Packit 2ba279
            BlockDev.md_deactivate(BlockDev.md_node_from_name("bd_test_md"))
Packit 2ba279
        except:
Packit 2ba279
            pass
Packit 2ba279
        try:
Packit 2ba279
            BlockDev.md_destroy(self.loop_dev)
Packit 2ba279
        except:
Packit 2ba279
            pass
Packit 2ba279
        try:
Packit 2ba279
            BlockDev.md_destroy(self.loop_dev2)
Packit 2ba279
        except:
Packit 2ba279
            pass
Packit 2ba279
        try:
Packit 2ba279
            BlockDev.md_destroy(self.loop_dev3)
Packit 2ba279
        except:
Packit 2ba279
            pass
Packit 2ba279
        try:
Packit 2ba279
            BlockDev.md_deactivate("bd_test_md")
Packit 2ba279
        except:
Packit 2ba279
            pass
Packit 2ba279
        try:
Packit 2ba279
            BlockDev.md_deactivate(BlockDev.md_node_from_name("bd_test_md"))
Packit 2ba279
        except:
Packit 2ba279
            pass
Packit 2ba279
Packit 2ba279
        try:
Packit 2ba279
            delete_lio_device(self.loop_dev)
Packit 2ba279
        except RuntimeError:
Packit 2ba279
            # just move on, we can do no better here
Packit 2ba279
            pass
Packit 2ba279
        os.unlink(self.dev_file)
Packit 2ba279
Packit 2ba279
        try:
Packit 2ba279
            delete_lio_device(self.loop_dev2)
Packit 2ba279
        except RuntimeError:
Packit 2ba279
            # just move on, we can do no better here
Packit 2ba279
            pass
Packit 2ba279
        os.unlink(self.dev_file2)
Packit 2ba279
Packit 2ba279
        try:
Packit 2ba279
            delete_lio_device(self.loop_dev3)
Packit 2ba279
        except RuntimeError:
Packit 2ba279
            # just move on, we can do no better here
Packit 2ba279
            pass
Packit 2ba279
        os.unlink(self.dev_file3)
Packit 2ba279
Packit 2ba279
Packit 2ba279
class MDTestCreateDeactivateDestroy(MDTestCase):
Packit 2ba279
    @tag_test(TestTags.SLOW, TestTags.CORE)
Packit 2ba279
    def test_create_deactivate_destroy(self):
Packit 2ba279
        """Verify that it is possible to create, deactivate and destroy an MD RAID"""
Packit 2ba279
Packit 2ba279
        with self.assertRaises(GLib.GError):
Packit 2ba279
            BlockDev.md_create("bd_test_md2", "raid1",
Packit 2ba279
                               ["/non/existing/device", self.loop_dev2],
Packit 2ba279
                               1, None, True)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid1",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2, self.loop_dev3],
Packit 2ba279
                                      1, None, True)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        # newly created array should be 'clean'
Packit 2ba279
        state = BlockDev.md_get_status("bd_test_md")
Packit 2ba279
        self.assertEqual(state, "clean")
Packit 2ba279
Packit 2ba279
        succ = BlockDev.md_deactivate("bd_test_md")
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        succ = BlockDev.md_destroy(self.loop_dev)
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
        succ = BlockDev.md_destroy(self.loop_dev2)
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
        succ = BlockDev.md_destroy(self.loop_dev3)
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
class MDTestCreateWithChunkSize(MDTestCase):
Packit 2ba279
    @tag_test(TestTags.SLOW)
Packit 2ba279
    def test_create_with_chunk_size(self):
Packit 2ba279
        """Verify that it is possible to create and MD RAID with specific chunk size """
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid0",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2],
Packit 2ba279
                                      0, None, False, 512 * 1024)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        ex_data = BlockDev.md_examine(self.loop_dev)
Packit 2ba279
        self.assertEqual(ex_data.chunk_size, 512 * 1024)
Packit 2ba279
Packit 2ba279
        succ = BlockDev.md_deactivate("bd_test_md")
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        succ = BlockDev.md_destroy(self.loop_dev)
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
        succ = BlockDev.md_destroy(self.loop_dev2)
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
        succ = BlockDev.md_destroy(self.loop_dev3)
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
class MDTestActivateDeactivate(MDTestCase):
Packit 2ba279
    @tag_test(TestTags.SLOW, TestTags.CORE)
Packit 2ba279
    def test_activate_deactivate(self):
Packit 2ba279
        """Verify that it is possible to activate and deactivate an MD RAID"""
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid1",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2, self.loop_dev3],
Packit 2ba279
                                      1, None, True)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        with self.assertRaises(GLib.GError):
Packit 2ba279
            BlockDev.md_deactivate("non_existing_md")
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_deactivate("bd_test_md")
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        with self.assertRaises(GLib.GError):
Packit 2ba279
            BlockDev.md_activate("bd_test_md",
Packit 2ba279
                                 ["/non/existing/device", self.loop_dev2, self.loop_dev3], None)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_activate("bd_test_md",
Packit 2ba279
                                        [self.loop_dev, self.loop_dev2, self.loop_dev3], None)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        # try to deactivate using the node instead of name
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_deactivate(BlockDev.md_node_from_name("bd_test_md"))
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        # try to activate using full path, not just the name
Packit 2ba279
        # (it should work too and blivet does this)
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_activate("/dev/md/bd_test_md",
Packit 2ba279
                                        [self.loop_dev, self.loop_dev2, self.loop_dev3], None)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
class MDTestActivateWithUUID(MDTestCase):
Packit 2ba279
    @tag_test(TestTags.SLOW)
Packit 2ba279
    def test_activate_with_uuid(self):
Packit 2ba279
        """Verify that it is possible to activate an MD RAID with UUID"""
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid1",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2, self.loop_dev3],
Packit 2ba279
                                      1, None, True)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_deactivate("bd_test_md")
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        md_info = BlockDev.md_examine(self.loop_dev)
Packit 2ba279
        self.assertTrue(md_info)
Packit 2ba279
        self.assertTrue(md_info.uuid)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_activate("bd_test_md", [self.loop_dev, self.loop_dev2, self.loop_dev3], md_info.uuid)
Packit 2ba279
Packit 2ba279
class MDTestActivateByUUID(MDTestCase):
Packit 2ba279
    @tag_test(TestTags.SLOW)
Packit 2ba279
    def test_activate_by_uuid(self):
Packit 2ba279
        """Verify that it is possible to activate an MD RAID by UUID"""
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid1",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2, self.loop_dev3],
Packit 2ba279
                                      1, None, True)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_deactivate("bd_test_md")
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        md_info = BlockDev.md_examine(self.loop_dev)
Packit 2ba279
        self.assertTrue(md_info)
Packit 2ba279
        self.assertTrue(md_info.uuid)
Packit 2ba279
Packit 2ba279
        # should work with member devices specified
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_activate(None, [self.loop_dev, self.loop_dev2, self.loop_dev3], md_info.uuid)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_deactivate("bd_test_md")
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        # as well as without them
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_activate(None, None, md_info.uuid)
Packit 2ba279
Packit 2ba279
Packit 2ba279
class MDTestNominateDenominate(MDTestCase):
Packit 2ba279
    @tag_test(TestTags.SLOW)
Packit 2ba279
    def test_nominate_denominate(self):
Packit 2ba279
        """Verify that it is possible to nominate and denominate an MD RAID device"""
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid1",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2, self.loop_dev3],
Packit 2ba279
                                      1, None, False)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_denominate(self.loop_dev)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_nominate(self.loop_dev)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_denominate(self.loop_dev)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_nominate(self.loop_dev)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_deactivate(BlockDev.md_node_from_name("bd_test_md"))
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
class MDTestNominateDenominateActive(MDTestCase):
Packit 2ba279
    # slow and leaking an MD array because with a nominated spare device, it
Packit 2ba279
    # cannot be deactivated in the end (don't ask me why)
Packit 2ba279
    @tag_test(TestTags.SLOW, TestTags.UNSAFE, TestTags.UNSTABLE)
Packit 2ba279
    def test_nominate_denominate_active(self):
Packit 2ba279
        """Verify that nominate and denominate deivice works as expected on (de)activated MD RAID"""
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid1",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2, self.loop_dev3],
Packit 2ba279
                                      1, None, False)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        # can not re-add in incremental mode because the array is active
Packit 2ba279
        with self.assertRaises(GLib.GError):
Packit 2ba279
            BlockDev.md_nominate(self.loop_dev3)
Packit 2ba279
Packit 2ba279
        succ = BlockDev.md_deactivate("bd_test_md");
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        # once the array is deactivated, can add in incremental mode
Packit 2ba279
        succ = BlockDev.md_nominate(self.loop_dev3)
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        # cannot re-add twice
Packit 2ba279
        with self.assertRaises(GLib.GError):
Packit 2ba279
            succ = BlockDev.md_nominate(self.loop_dev3)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
class MDTestAddRemove(MDTestCase):
Packit 2ba279
    @tag_test(TestTags.SLOW)
Packit 2ba279
    def test_add_remove(self):
Packit 2ba279
        """Verify that it is possible to add a device to and remove from an MD RAID"""
Packit 2ba279
Packit 2ba279
        # the MD array doesn't exist yet
Packit 2ba279
        with self.assertRaises(GLib.GError):
Packit 2ba279
            BlockDev.md_add("bd_test_md", self.loop_dev3, 0, None)
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid1",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2],
Packit 2ba279
                                      0, None, False)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        with self.assertRaises(GLib.GError):
Packit 2ba279
            BlockDev.md_add("bd_test_md", "/non/existing/device", 0, None)
Packit 2ba279
Packit 2ba279
        # add the device as a spare
Packit 2ba279
        succ = BlockDev.md_add("bd_test_md", self.loop_dev3, 0, None)
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        md_info = BlockDev.md_detail("bd_test_md")
Packit 2ba279
        self.assertEqual(md_info.raid_devices, 2)
Packit 2ba279
        self.assertEqual(md_info.spare_devices, 1)
Packit 2ba279
Packit 2ba279
        with self.assertRaises(GLib.GError):
Packit 2ba279
            BlockDev.md_add("bd_test_md", self.loop_dev3, 0, None)
Packit 2ba279
Packit 2ba279
        # now remove the spare device (should be possible without --fail)
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_remove("bd_test_md", self.loop_dev3, False, None)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        md_info = BlockDev.md_detail("bd_test_md")
Packit 2ba279
        self.assertEqual(md_info.raid_devices, 2)
Packit 2ba279
        self.assertEqual(md_info.spare_devices, 0)
Packit 2ba279
Packit 2ba279
        # remove one of the original devices (with --fail enabled)
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_remove("bd_test_md", self.loop_dev2, True, None)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        md_info = BlockDev.md_detail("bd_test_md")
Packit 2ba279
        self.assertEqual(md_info.raid_devices, 2)
Packit 2ba279
        self.assertEqual(md_info.active_devices, 1)
Packit 2ba279
        self.assertEqual(md_info.spare_devices, 0)
Packit 2ba279
Packit 2ba279
        # now try to add it back -- it should be re-added automatically as
Packit 2ba279
        # a RAID device, not a spare device
Packit 2ba279
        with wait_for_action("recovery"):
Packit 2ba279
            succ = BlockDev.md_add("bd_test_md", self.loop_dev2, 0, None)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        md_info = BlockDev.md_detail("bd_test_md")
Packit 2ba279
        self.assertEqual(md_info.raid_devices, 2)
Packit 2ba279
        self.assertEqual(md_info.active_devices, 2)
Packit 2ba279
        self.assertEqual(md_info.spare_devices, 0)
Packit 2ba279
Packit 2ba279
class MDTestExamineDetail(MDTestCase):
Packit 2ba279
    # sleeps to let MD RAID sync things
Packit 2ba279
    @tag_test(TestTags.SLOW)
Packit 2ba279
    def test_examine_detail(self):
Packit 2ba279
        """Verify that it is possible to get info about an MD RAID"""
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid1",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2, self.loop_dev3],
Packit 2ba279
                                      1, None, True)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        ex_data = BlockDev.md_examine(self.loop_dev)
Packit 2ba279
        # test that we got something
Packit 2ba279
        self.assertTrue(ex_data)
Packit 2ba279
Packit 2ba279
        # verify some known data
Packit 2ba279
        self.assertEqual(ex_data.device, "/dev/md/bd_test_md")
Packit 2ba279
        self.assertEqual(ex_data.level, "raid1")
Packit 2ba279
        self.assertEqual(ex_data.num_devices, 2)
Packit 2ba279
        self.assertTrue(ex_data.name.endswith("bd_test_md"))
Packit 2ba279
        self.assertEqual(len(ex_data.metadata), 3)
Packit 2ba279
        self.assertTrue(ex_data.size < (10 * 1024**2))
Packit 2ba279
        self.assertTrue(re.match(r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', ex_data.uuid))
Packit 2ba279
Packit 2ba279
        de_data = BlockDev.md_detail("bd_test_md")
Packit 2ba279
        # test that we got something
Packit 2ba279
        self.assertTrue(de_data)
Packit 2ba279
Packit 2ba279
        # verify some known data
Packit 2ba279
        self.assertEqual(de_data.device, "/dev/md/bd_test_md")
Packit 2ba279
        self.assertTrue(de_data.name.endswith("bd_test_md"))
Packit 2ba279
        self.assertEqual(len(de_data.metadata), 3)
Packit 2ba279
        self.assertEqual(de_data.level, "raid1")
Packit 2ba279
        self.assertEqual(de_data.raid_devices, 2)
Packit 2ba279
        self.assertEqual(de_data.total_devices, 3)
Packit 2ba279
        self.assertEqual(de_data.spare_devices, 1)
Packit 2ba279
        self.assertTrue(de_data.array_size < (10 * 1024**2))
Packit 2ba279
        self.assertTrue(de_data.use_dev_size < (10 * 1024**2))
Packit 2ba279
        if "JENKINS_HOME" not in os.environ:
Packit 2ba279
            # XXX: for some reason the RAID is in "active sync" when tests run in
Packit 2ba279
            # Jenkins
Packit 2ba279
            self.assertTrue(de_data.clean)
Packit 2ba279
        self.assertTrue(re.match(r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', de_data.uuid))
Packit 2ba279
Packit 2ba279
        self.assertEqual(ex_data.uuid, de_data.uuid)
Packit 2ba279
Packit 2ba279
        # try to get detail data with some different raid specification
Packit 2ba279
        node = BlockDev.md_node_from_name("bd_test_md")
Packit 2ba279
Packit 2ba279
        de_data = BlockDev.md_detail("/dev/md/bd_test_md")
Packit 2ba279
        self.assertTrue(de_data)
Packit 2ba279
        de_data = BlockDev.md_detail(node)
Packit 2ba279
        self.assertTrue(de_data)
Packit 2ba279
        de_data = BlockDev.md_detail("/dev/%s" % node)
Packit 2ba279
        self.assertTrue(de_data)
Packit 2ba279
Packit 2ba279
class MDTestNameNodeBijection(MDTestCase):
Packit 2ba279
    @tag_test(TestTags.SLOW)
Packit 2ba279
    def test_name_node_bijection(self):
Packit 2ba279
        """Verify that MD RAID node and name match each other"""
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid1",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2, self.loop_dev3],
Packit 2ba279
                                      1, None, True)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        node = BlockDev.md_node_from_name("bd_test_md")
Packit 2ba279
        self.assertEqual(BlockDev.md_name_from_node(node), "bd_test_md")
Packit 2ba279
        self.assertEqual(BlockDev.md_name_from_node("/dev/" + node), "bd_test_md")
Packit 2ba279
Packit 2ba279
        with self.assertRaises(GLib.GError):
Packit 2ba279
            node = BlockDev.md_node_from_name("made_up_md")
Packit 2ba279
Packit 2ba279
        with six.assertRaisesRegex(self, GLib.GError, r'No name'):
Packit 2ba279
            BlockDev.md_name_from_node("no_such_node")
Packit 2ba279
Packit 2ba279
        succ = BlockDev.md_deactivate("bd_test_md");
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        succ = BlockDev.md_destroy(self.loop_dev)
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
        succ = BlockDev.md_destroy(self.loop_dev2)
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
        succ = BlockDev.md_destroy(self.loop_dev3)
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
class MDTestSetBitmapLocation(MDTestCase):
Packit 2ba279
    @tag_test(TestTags.SLOW, TestTags.UNSTABLE)
Packit 2ba279
    def test_set_bitmap_location(self):
Packit 2ba279
        """Verify we can change bitmap location for an existing MD array"""
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid1",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2, self.loop_dev3],
Packit 2ba279
                                      1, None, True)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        succ = BlockDev.md_set_bitmap_location("bd_test_md", "none")
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        loc = BlockDev.md_get_bitmap_location("bd_test_md")
Packit 2ba279
        self.assertEqual(loc, "none")
Packit 2ba279
Packit 2ba279
        succ = BlockDev.md_set_bitmap_location("bd_test_md", "internal")
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        loc = BlockDev.md_get_bitmap_location("bd_test_md")
Packit 2ba279
        self.assertEqual(loc, "+8")
Packit 2ba279
Packit 2ba279
        # test some different name specifications
Packit 2ba279
        # (need to switch between internal and none because setting the same
Packit 2ba279
        # location multiple times results in an error)
Packit 2ba279
        succ = BlockDev.md_set_bitmap_location("/dev/md/bd_test_md", "none")
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        node = BlockDev.md_node_from_name("bd_test_md")
Packit 2ba279
        self.assertIsNotNone(node)
Packit 2ba279
Packit 2ba279
        succ = BlockDev.md_set_bitmap_location(node, "internal")
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        succ = BlockDev.md_set_bitmap_location("/dev/%s" % node, "none")
Packit 2ba279
        self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        # get_bitmap_location should accept name, node or path
Packit 2ba279
        loc = BlockDev.md_get_bitmap_location(node)
Packit 2ba279
        self.assertEqual(loc, "none")
Packit 2ba279
Packit 2ba279
        loc = BlockDev.md_get_bitmap_location("/dev/%s" % node)
Packit 2ba279
        self.assertEqual(loc, "none")
Packit 2ba279
Packit 2ba279
        loc = BlockDev.md_get_bitmap_location("/dev/md/bd_test_md")
Packit 2ba279
        self.assertEqual(loc, "none")
Packit 2ba279
Packit 2ba279
Packit 2ba279
class MDTestRequestSyncAction(MDTestCase):
Packit 2ba279
    @tag_test(TestTags.SLOW)
Packit 2ba279
    def test_request_sync_action(self):
Packit 2ba279
        """Verify we can request sync action on an existing MD array"""
Packit 2ba279
Packit 2ba279
        with wait_for_action("resync"):
Packit 2ba279
            succ = BlockDev.md_create("bd_test_md", "raid1",
Packit 2ba279
                                      [self.loop_dev, self.loop_dev2, self.loop_dev3],
Packit 2ba279
                                      1, None, True)
Packit 2ba279
            self.assertTrue(succ)
Packit 2ba279
Packit 2ba279
        with wait_for_action("check"):
Packit 2ba279
            succ = BlockDev.md_request_sync_action("bd_test_md", "check")
Packit 2ba279
Packit 2ba279
        node = BlockDev.md_node_from_name("bd_test_md")
Packit 2ba279
        with open("/sys/block/%s/md/last_sync_action" % node) as f:
Packit 2ba279
            action = f.read().strip()
Packit 2ba279
        self.assertEqual(action, "check")
Packit 2ba279
Packit 2ba279
class FakeMDADMutilTest(MDTest):
Packit 2ba279
    # no setUp nor tearDown needed, we are gonna use fake utils
Packit 2ba279
    @tag_test(TestTags.NOSTORAGE)
Packit 2ba279
    def test_fw_raid_uppercase_examine(self):
Packit 2ba279
        """Verify that md_examine works with output using "RAID" instead of "Raid" and other quirks """
Packit 2ba279
Packit 2ba279
        with fake_utils("tests/mdadm_fw_RAID_examine"):
Packit 2ba279
            ex_data = BlockDev.md_examine("fake_dev")
Packit 2ba279
Packit 2ba279
        self.assertEqual(ex_data.level, "container")
Packit 2ba279
        self.assertEqual(ex_data.num_devices, 1)
Packit 2ba279
        self.assertEqual(ex_data.uuid, "b42756a2-37e4-3e47-674b-d1dd6e822145")
Packit 2ba279
        self.assertEqual(ex_data.device, None)
Packit 2ba279
Packit 2ba279
    @tag_test(TestTags.NOSTORAGE)
Packit 2ba279
    def test_no_metadata_examine(self):
Packit 2ba279
        """Verify that md_examine works as expected with no metadata spec"""
Packit 2ba279
Packit 2ba279
        # shouldn't raise any exception
Packit 2ba279
        with fake_utils("tests/mdadm_no_metadata_examine"):
Packit 2ba279
            ex_data = BlockDev.md_examine("fake_dev")
Packit 2ba279
Packit 2ba279
        self.assertIs(ex_data.metadata, None)
Packit 2ba279
Packit 2ba279
    @tag_test(TestTags.NOSTORAGE)
Packit 2ba279
    def test_fw_raid_migrating(self):
Packit 2ba279
        """Verify that md_examine works when array is migrating ("foo <-- bar" values in output) """
Packit 2ba279
Packit 2ba279
        with fake_utils("tests/mdadm_fw_RAID_examine_migrate"):
Packit 2ba279
            ex_data = BlockDev.md_examine("fake_dev")
Packit 2ba279
Packit 2ba279
        self.assertEqual(ex_data.chunk_size, 128 * 1024)
Packit 2ba279
Packit 2ba279
    @tag_test(TestTags.NOSTORAGE)
Packit 2ba279
    def test_mdadm_name_extra_info(self):
Packit 2ba279
        """Verify that md_examine and md_detail work with extra MD RAID name info"""
Packit 2ba279
Packit 2ba279
        with fake_utils("tests/mdadm_extra_name_stuff"):
Packit 2ba279
            ex_data = BlockDev.md_examine("fake_dev")
Packit 2ba279
            detail_data = BlockDev.md_detail("fake_dev")
Packit 2ba279
Packit 2ba279
        self.assertEqual(ex_data.name, "localhost:fedora")
Packit 2ba279
        self.assertEqual(detail_data.name, "localhost:fedora")
Packit 2ba279
Packit 2ba279
Packit 2ba279
class MDUnloadTest(MDTestCase):
Packit 2ba279
    def setUp(self):
Packit 2ba279
        # make sure the library is initialized with all plugins loaded for other
Packit 2ba279
        # tests
Packit 2ba279
        self.addCleanup(BlockDev.reinit, self.requested_plugins, True, None)
Packit 2ba279
Packit 2ba279
    @tag_test(TestTags.NOSTORAGE)
Packit 2ba279
    def test_check_low_version(self):
Packit 2ba279
        """Verify that checking the minimum mdsetup version works as expected"""
Packit 2ba279
Packit 2ba279
        # unload all plugins first
Packit 2ba279
        self.assertTrue(BlockDev.reinit([], True, None))
Packit 2ba279
Packit 2ba279
        with fake_utils("tests/mdraid_low_version/"):
Packit 2ba279
            # too low version of mdsetup available, the MD plugin should fail to load
Packit 2ba279
            with self.assertRaises(GLib.GError):
Packit 2ba279
                BlockDev.reinit(self.requested_plugins, True, None)
Packit 2ba279
Packit 2ba279
            self.assertNotIn("mdraid", BlockDev.get_available_plugin_names())
Packit 2ba279
Packit 2ba279
        # load the plugins back
Packit 2ba279
        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
Packit 2ba279
        self.assertIn("mdraid", BlockDev.get_available_plugin_names())
Packit 2ba279
Packit 2ba279
    @tag_test(TestTags.NOSTORAGE)
Packit 2ba279
    def test_check_no_md(self):
Packit 2ba279
        """Verify that checking mdsetup tool availability works as expected"""
Packit 2ba279
Packit 2ba279
        # unload all plugins first
Packit 2ba279
        self.assertTrue(BlockDev.reinit([], True, None))
Packit 2ba279
Packit 2ba279
        with fake_path(all_but="mdadm"):
Packit 2ba279
            # no mdadm available, the MD plugin should fail to load
Packit 2ba279
            with self.assertRaises(GLib.GError):
Packit 2ba279
                BlockDev.reinit(self.requested_plugins, True, None)
Packit 2ba279
Packit 2ba279
            self.assertNotIn("mdraid", BlockDev.get_available_plugin_names())
Packit 2ba279
Packit 2ba279
        # load the plugins back
Packit 2ba279
        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
Packit 2ba279
        self.assertIn("mdraid", BlockDev.get_available_plugin_names())