Exemple #1
0
    def __exit__(self, exception_type, exception_value, traceback):
        try:
            for (key_desc, _) in reversed(self._key_descs):
                (_, return_code,
                 message) = Manager.Methods.UnsetKey(get_object(TOP_OBJECT),
                                                     {"key_desc": key_desc})

                if return_code != StratisdErrors.OK:
                    raise RuntimeError(
                        "Unsetting the key using stratisd failed with an error: %s"
                        % message)

        except RuntimeError as rexc:
            if exception_value is None:
                raise rexc
            raise rexc from exception_value
Exemple #2
0
def get_pools(name=None):
    """
    Returns a list of all pools found by GetManagedObjects, or a list
    of pools with names matching the specified name, if passed.
    :param name: filter for pool name
    :type name: str or NoneType
    :return: list of pool information found
    :rtype: list of (str * MOPool)
    """
    managed_objects = ObjectManager.Methods.GetManagedObjects(
        get_object(TOP_OBJECT), {})

    return [(op, MOPool(info))
            for op, info in pools(props={} if name is None else {
                "Name": name
            }).search(managed_objects)]
Exemple #3
0
 def setUp(self):
     """
     Start the stratisd daemon with the simulator.
     """
     super().setUp()
     self._proxy = get_object(TOP_OBJECT)
     self._blockdevs = ["/dev/one", "/dev/two", "/dev/red", "/dev/blue"]
     Manager.Methods.CreatePool(
         self._proxy,
         {
             "name": self._POOLNAME,
             "redundancy": (True, 0),
             "devices": self._blockdevs,
         },
     )
     Manager.Methods.ConfigureSimulator(self._proxy, {"denominator": 8})
Exemple #4
0
 def setUp(self):
     """
     Start the stratisd daemon with the simulator.
     """
     self._service = Service()
     self._service.setUp()
     time.sleep(1)
     self._proxy = get_object(TOP_OBJECT)
     self._errors = StratisdErrorsGen.get_object()
     Manager.CreatePool(
        self._proxy,
        name=self._POOLNAME,
        redundancy=0,
        force=False,
        devices=[d.device_node for d in _device_list(_DEVICES, 1)]
     )
     Manager.ConfigureSimulator(self._proxy, denominator=8)
Exemple #5
0
    def create_volumes(namespace):
        """
        Create volumes in a pool.

        :raises StratisCliRuntimeError:
        """
        proxy = get_object(TOP_OBJECT)
        pool_object = get_pool(proxy, namespace.pool)

        volume_list = [(x, '', None) for x in namespace.volume]
        (_, rc, message) = \
           Pool.CreateFilesystems(pool_object, specs=volume_list)

        if rc != StratisdErrorsGen().get_object().OK:
            raise StratisCliRuntimeError(rc, message)

        return
Exemple #6
0
    def destroy_pool(namespace):
        """
        Destroy a stratis pool.

        If no pool exists, the method succeeds.

        :raises StratisCliRuntimeError:
        """
        proxy = get_object(TOP_OBJECT)

        (rc, message) = Manager.DestroyPool(proxy, name=namespace.name)

        stratisd_errors = StratisdErrorsGen.get_object()

        if rc != stratisd_errors.OK:
            raise StratisCliRuntimeError(rc, message)

        return
Exemple #7
0
def get_cache(top, pool):
    """
    Get cache given ``pool``.

    :param top: the top object
    :param str pool: the name of the pool

    :returns: the corresponding object
    :rtype: ProxyObject
    :raises StratisCliRuntimeError: if failure to get object
    """
    (cache_object_path, rc, message) = \
       Manager.GetCacheObjectPath(top, name=pool)

    if rc != StratisdErrorsGen.get_object().OK:
        raise StratisCliRuntimeError(rc, message)

    return get_object(cache_object_path)
 def setUp(self):
     """
     Start the stratisd daemon with the simulator.
     """
     self._service = Service()
     self._service.setUp()
     time.sleep(1)
     self._proxy = get_object(TOP_OBJECT)
     Manager.Methods.CreatePool(
        self._proxy,
        {
           'name': self._POOLNAME,
           'redundancy': (True, 0),
           'force': False,
           'devices': []
        }
     )
     Manager.Methods.ConfigureSimulator(self._proxy, {'denominator': 8})
Exemple #9
0
    def list_pools(namespace):
        """
        List all stratis pools.

        :raises StratisCliRuntimeError:
        """
        # pylint: disable=unused-argument
        proxy = get_object(TOP_OBJECT)

        (result, rc, message) = Manager.ListPools(proxy)

        stratisd_errors = StratisdErrorsGen.get_object()
        if rc != stratisd_errors.OK:
            raise StratisCliRuntimeError(rc, message)

        for item in result:
            print(item)

        return
Exemple #10
0
    def testNonExisting(self):
        """
        A proxy object is returned from a non-existant path.
        """
        proxy = get_object('/this/is/not/an/object/path')
        self.assertIsNotNone(proxy)

        with self.assertRaises(DPClientInvocationError) as context:
            ObjectManager.Methods.GetManagedObjects(proxy, {})
        cause = context.exception.__cause__
        self.assertIsInstance(cause, dbus.exceptions.DBusException)
        self.assertEqual(cause.get_dbus_name(),
                         'org.freedesktop.DBus.Error.UnknownMethod')

        with self.assertRaises(DPClientInvocationError) as context:
            Manager.Properties.Version.Get(proxy)
        cause = context.exception.__cause__
        self.assertIsInstance(cause, dbus.exceptions.DBusException)
        self.assertEqual(cause.get_dbus_name(),
                         'org.freedesktop.DBus.Error.UnknownMethod')
Exemple #11
0
    def testNewName(self):
        """
        Test rename to new name.
        """
        filesystem = get_object(self._filesystem_object_path)
        (result, rc, _) = Filesystem.Methods.SetName(filesystem,
                                                     {'name': "new"})

        self.assertEqual(rc, StratisdErrors.OK)
        self.assertTrue(result)

        managed_objects = \
           ObjectManager.Methods.GetManagedObjects(self._proxy, {})
        (fs_object_path, _) = next(
            filesystems(managed_objects, {'Name': 'new'}))
        self.assertEqual(self._filesystem_object_path, fs_object_path)

        fs_object_path = \
           next(filesystems(managed_objects, {'Name': self._fs_name}), None)
        self.assertIsNone(fs_object_path)
Exemple #12
0
    def create_pool(namespace):
        """
        Create a stratis pool.

        :raises StratisCliRuntimeError:
        """
        stratisd_errors = StratisdErrorsGen.get_object()

        proxy = get_object(TOP_OBJECT)

        (_, rc, message) = Manager.CreatePool(proxy,
                                              name=namespace.name,
                                              redundancy=0,
                                              force=namespace.force,
                                              devices=namespace.device)

        if rc != stratisd_errors.OK:
            raise StratisCliRuntimeError(rc, message)

        return
Exemple #13
0
    def testNewName(self):
        """
        Test rename to new name.
        """
        filesystem = get_object(self._filesystem_object_path)
        (result, rc,
         _) = checked_call(Filesystem.SetName(filesystem, name="new"),
                           FilesystemSpec.OUTPUT_SIGS[_FN.SetName])

        self.assertEqual(rc, self._errors.OK)
        self.assertTrue(result)

        managed_objects = get_managed_objects(self._proxy)
        (fs_object_path, _) = next(managed_objects.filesystems({'Name':
                                                                'new'}))
        self.assertEqual(self._filesystem_object_path, fs_object_path)

        fs_object_path = \
           next(managed_objects.filesystems({'Name': self._fs_name}), None)
        self.assertIsNone(fs_object_path)
    def _test_prediction(self, pool_name, *, fs_specs=None, overprovision=True):
        """
        Helper function to verify that the prediction matches the reality to
        an acceptable degree.

        :param str pool_name: the name of the pool to test
        :param fs_specs: filesystems to create and test
        :type fs_specs: list of of str * Range or NoneType
        :param bool overprovision: True if overprovisioning is allowed
        """
        proxy = get_object(TOP_OBJECT)

        managed_objects = ObjectManager.Methods.GetManagedObjects(proxy, {})

        pool_object_path, pool = next(
            pools(props={"Name": pool_name})
            .require_unique_match(True)
            .search(managed_objects)
        )

        mopool = MOPool(pool)

        physical_sizes = _get_block_device_sizes(pool_object_path, managed_objects)
        pre_prediction = _call_predict_usage(
            mopool.Encrypted(), physical_sizes, overprovision=overprovision
        )

        self._check_prediction(pre_prediction, mopool)

        change = _possibly_add_filesystems(pool_object_path, fs_specs=fs_specs)

        post_prediction = _call_predict_usage(
            mopool.Encrypted(),
            physical_sizes,
            fs_specs=fs_specs,
            overprovision=overprovision,
        )

        self._check_fs_prediction(
            pre_prediction, post_prediction, change, overprovision=overprovision
        )
Exemple #15
0
def get_volume(top, pool, name):
    """
    Get volume given ``name`` and ``pool``.

    :param top: the top object
    :param str pool: the object path of the pool
    :param str name: the name of the volume

    :returns: the corresponding object
    :rtype: ProxyObject
    :raises StratisCliRuntimeError: if failure to get object
    """
    (volume_object_path, rc,
     message) = Manager.GetFilesystemObjectPath(top,
                                                pool_name=pool,
                                                filesystem_name=name)

    if rc != StratisdErrorsGen.get_object().OK:
        raise StratisCliRuntimeError(rc, message)

    return get_object(volume_object_path)
Exemple #16
0
    def test_props(self):
        """
        Test reading some filesystem properties.
        """
        filesystem = get_object(self._filesystem_object_path)
        name = Filesystem.Properties.Name.Get(filesystem)

        self.assertEqual(self._FSNAME, name)

        uuid = Filesystem.Properties.Uuid.Get(filesystem)

        # must be a 32 character string
        self.assertEqual(32, len(uuid))

        created = Filesystem.Properties.Created.Get(filesystem)

        # Should be a UTC rfc3339 string, which should end in Z
        self.assertTrue(created.endswith("Z"))
        # I think this is also always true
        self.assertEqual(len(created), 20)

        devnode = Filesystem.Properties.Devnode.Get(filesystem)
        self.assertTrue(isabs(devnode))
Exemple #17
0
    def testNewName(self):
        """
        Test rename to new name.
        """
        filesystem = get_object(self._filesystem_object_path)
        (result, rc, _) = Filesystem.Methods.SetName(filesystem,
                                                     {"name": "new"})

        self.assertEqual(rc, StratisdErrors.OK)
        self.assertTrue(result)

        managed_objects = ObjectManager.Methods.GetManagedObjects(
            self._proxy, {})
        (fs_object_path,
         _) = next(filesystems(props={
             "Name": "new"
         }).search(managed_objects))
        self.assertEqual(self._filesystem_object_path, fs_object_path)

        fs_object_path = next(
            filesystems(props={
                "Name": self._FSNAME
            }).search(managed_objects), None)
        self.assertIsNone(fs_object_path)
Exemple #18
0
    def test_duplicate_pool_name(self):  # pylint: disable=too-many-locals
        """
        Create more than one pool with the same name, then dynamically fix it
        :return: None
        """
        pool_name = random_string(12)
        pool_tokens = []
        encrypted_indices = []
        unencrypted_indices = []
        num_pools = 3
        keys = [
            ("key_desc_1", "key_data_1"),
            ("key_desc_2", "key_data_2"),
            ("key_desc_3", "key_data_3"),
        ]

        # Create some pools with duplicate names
        for i in range(num_pools):
            this_pool = self._lb_mgr.create_devices(i + 1)
            devnodes = self._lb_mgr.device_files(this_pool)

            with OptionalKeyServiceContextManager(
                    key_spec=keys) as key_descriptions:
                key_description = (key_descriptions[random.randint(
                    0,
                    len(key_descriptions) -
                    1)] if random.choice([True, False]) else None)
                create_pool(pool_name,
                            devnodes,
                            key_description=key_description)
                if key_description is None:
                    unencrypted_indices.append(i)
                else:
                    encrypted_indices.append(i)

            pool_tokens.append(this_pool)

            remove_stratis_dm_devices()

            self._lb_mgr.unplug(this_pool)

            wait_for_udev(STRATIS_FS_TYPE, [])

        all_tokens = [dev for sublist in pool_tokens for dev in sublist]
        random.shuffle(all_tokens)

        with OptionalKeyServiceContextManager(key_spec=keys):
            self._lb_mgr.hotplug(all_tokens)

            (luks_tokens, non_luks_tokens) = (
                [
                    dev
                    for sublist in (pool_tokens[i] for i in encrypted_indices)
                    for dev in sublist
                ],
                [
                    dev for sublist in (pool_tokens[i]
                                        for i in unencrypted_indices)
                    for dev in sublist
                ],
            )

            wait_for_udev(CRYPTO_LUKS_FS_TYPE,
                          self._lb_mgr.device_files(luks_tokens))
            wait_for_udev(STRATIS_FS_TYPE,
                          self._lb_mgr.device_files(non_luks_tokens))

            (valid,
             variant_pool_uuids) = FetchPropertiesR1.Methods.GetProperties(
                 get_object(TOP_OBJECT),
                 {"properties": [LOCKED_POOL_UUIDS_PROP_NAME]
                  })[LOCKED_POOL_UUIDS_PROP_NAME]

            self.assertTrue(valid)

            for pool_uuid in variant_pool_uuids:
                ((option, _), exit_code,
                 _) = ManagerR1.Methods.UnlockPool(get_object(TOP_OBJECT),
                                                   {"pool_uuid": pool_uuid})
                self.assertEqual(exit_code, StratisdErrors.OK)
                self.assertEqual(option, True)

            wait_for_udev_count(len(all_tokens))

            # The number of pools should never exceed one, since all the pools
            # previously formed in the test have the same name.
            self.assertEqual(len(get_pools()), 1)

            # Dynamically rename all active pools to a randomly chosen name,
            # then generate synthetic add events for every loopbacked device.
            # After num_pools - 1 iterations, all pools should have been set up.
            for _ in range(num_pools - 1):
                current_pools = get_pools()

                # Rename all active pools to a randomly selected new name
                for object_path, _ in current_pools:
                    PoolR1.Methods.SetName(get_object(object_path),
                                           {"name": random_string(10)})

                self._lb_mgr.generate_synthetic_udev_events(
                    all_tokens, UDEV_ADD_EVENT)

                settle()

                self.assertEqual(len(get_pools()), len(current_pools) + 1)

            self.assertEqual(len(get_pools()), num_pools)

        remove_stratis_dm_devices()
Exemple #19
0
 def testExecution(self):
     """
     An exception is raised if the volume does not exist.
     """
     self.assertIsNotNone(get_cache(get_object(TOP_OBJECT), self._POOLNAME))
Exemple #20
0
 def testInvalid(self):
     """
     An invalid path causes an exception to be raised.
     """
     with self.assertRaises(ValueError):
         get_object('abc')
Exemple #21
0
    def _simple_event_test(self, *, key_spec=None):  # pylint: disable=too-many-locals
        """
        A simple test of event-based discovery.

        * Create just one pool.
        * Stop the daemon.
        * Unplug the devices.
        * Start the daemon.
        * Plug the devices in one by one. The pool should come up when the last
        device is plugged in.

        :param key_spec: specification for a key to be inserted into the kernel
                         keyring consisting of the key description and key data
        :type key_spec: (str, bytes) or NoneType
        """
        num_devices = 3
        udev_wait_type = STRATIS_FS_TYPE if key_spec is None else CRYPTO_LUKS_FS_TYPE
        device_tokens = self._lb_mgr.create_devices(num_devices)
        devnodes = self._lb_mgr.device_files(device_tokens)
        key_spec = None if key_spec is None else [key_spec]

        with OptionalKeyServiceContextManager(
                key_spec=key_spec) as key_descriptions:
            key_description = None if key_spec is None else key_descriptions[0]

            self.assertEqual(len(get_pools()), 0)
            (_, (pool_object_path,
                 _)) = create_pool(random_string(5),
                                   devnodes,
                                   key_description=key_description)
            pool_uuid = PoolR1.Properties.Uuid.Get(
                get_object(pool_object_path))

            self.assertEqual(len(get_pools()), 1)

        remove_stratis_dm_devices()

        self._lb_mgr.unplug(device_tokens)
        wait_for_udev(udev_wait_type, [])

        with OptionalKeyServiceContextManager(key_spec=key_spec):
            self.assertEqual(len(get_pools()), 0)

            indices = list(range(num_devices))
            random.shuffle(indices)

            tokens_up = []
            for index in indices[:-1]:
                tokens_up.append(device_tokens[index])
                self._lb_mgr.hotplug([tokens_up[-1]])
                wait_for_udev(udev_wait_type,
                              self._lb_mgr.device_files(tokens_up))
                self.assertEqual(len(get_pools()), 0)

            ((option, unlock_uuids), exit_code,
             _) = ManagerR1.Methods.UnlockPool(get_object(TOP_OBJECT),
                                               {"pool_uuid": pool_uuid})
            if key_spec is None:
                self.assertNotEqual(exit_code, StratisdErrors.OK)
                self.assertEqual(option, False)
            else:
                self.assertEqual(exit_code, StratisdErrors.OK)
                self.assertEqual(option, True)
                self.assertEqual(len(unlock_uuids), num_devices - 1)

            self.assertEqual(len(get_pools()), 0)

            tokens_up.append(device_tokens[indices[-1]])
            self._lb_mgr.hotplug([tokens_up[-1]])

            wait_for_udev(udev_wait_type, self._lb_mgr.device_files(tokens_up))

            ((option, unlock_uuids), exit_code,
             _) = ManagerR1.Methods.UnlockPool(get_object(TOP_OBJECT),
                                               {"pool_uuid": pool_uuid})

            if key_spec is None:
                self.assertNotEqual(exit_code, StratisdErrors.OK)
                self.assertEqual(option, False)
            else:
                self.assertEqual(exit_code, StratisdErrors.OK)
                self.assertEqual(option, True)
                self.assertEqual(len(unlock_uuids), 1)

            wait_for_udev_count(num_devices)

            self.assertEqual(len(get_pools()), 1)

        remove_stratis_dm_devices()
Exemple #22
0
 def testArguments(self):
     """
     Incorrect arguments should cause a type error.
     """
     with self.assertRaises(TypeError):
         Manager.Properties.Version.Get(get_object(TOP_OBJECT), {})
Exemple #23
0
 def testNonExisting(self):
     """
     A proxy object is returned from a non-existant path.
     """
     self.assertIsNotNone(get_object('/this/is/not/an/object/path'))
 def testStratisVersion(self):
     """
     Getting version should just succeed.
     """
     # pylint: disable=no-self-use
     Manager.Properties.Version(get_object(TOP_OBJECT))
Exemple #25
0
 def setUp(self):
     """
     Start stratisd.
     """
     super().setUp()
     self._proxy = get_object(TOP_OBJECT)
Exemple #26
0
    def _simple_initial_discovery_test(self,
                                       *,
                                       key_spec=None,
                                       take_down_dm=False):  # pylint: disable=too-many-locals
        """
        A simple test of discovery on start up.

        * Create just one pool
        * Stop the daemon
        * Restart the daemon and verify that the pool is found

        :param key_spec: specification for a key to be inserted into the kernel
                         keyring consisting of the key description and key data
        :type key_spec: (str, bytes) or NoneType
        :param bool take_down_dm: if True take down all Stratis devicemapper
        devices once stratisd is shut down
        """
        num_devices = 3
        device_tokens = self._lb_mgr.create_devices(num_devices)
        devnodes = self._lb_mgr.device_files(device_tokens)
        key_spec = None if key_spec is None else [key_spec]

        with OptionalKeyServiceContextManager(
                key_spec=key_spec) as key_descriptions:
            key_description = None if key_spec is None else key_descriptions[0]

            self.wait_for_pools(0)
            (_, (pool_object_path, device_object_paths)) = create_pool(
                random_string(5), devnodes, key_description=key_description)
            pool_uuid = Pool.Properties.Uuid.Get(get_object(pool_object_path))

            self.wait_for_pools(1)

            wait_for_udev(STRATIS_FS_TYPE, get_devnodes(device_object_paths))

        if take_down_dm:
            remove_stratis_dm_devices()

        with OptionalKeyServiceContextManager(key_spec=key_spec):
            ((option, unlock_uuids), exit_code,
             _) = Manager.Methods.UnlockPool(
                 get_object(TOP_OBJECT),
                 {
                     "pool_uuid": pool_uuid,
                     "unlock_method": str(EncryptionMethod.KEYRING),
                 },
             )
            if key_spec is None:
                self.assertNotEqual(exit_code, StratisdErrors.OK)
                self.assertEqual(option, False)
            else:
                self.assertEqual(exit_code, StratisdErrors.OK)
                self.assertEqual(option, take_down_dm)
                self.assertEqual(len(unlock_uuids),
                                 num_devices if take_down_dm else 0)

            wait_for_udev_count(num_devices)

            self.wait_for_pools(1)

        remove_stratis_dm_devices()
Exemple #27
0
 def testNonExistingVolume(self):
     """
     An exception is raised if the volume does not exist.
     """
     self.assertIsNotNone(get_pool(get_object(TOP_OBJECT), self._POOLNAME))
Exemple #28
0
    def test_duplicate_pool_name(self):
        """
        Create more than one pool with the same name, then dynamically fix it
        :return: None
        """
        pool_name = rs(12)
        pool_tokens = []
        num_pools = 3

        self._start_service()

        # Create some pools with duplicate names
        for i in range(num_pools):
            this_pool = [self._lb_mgr.create_device() for _ in range(i + 1)]

            # Ensure newly created block devices are in udev db.
            self._settle()

            pool_tokens.append(this_pool)
            UdevAdd._create_pool(pool_name, self._device_files(this_pool))
            devices = self._device_files(this_pool)

            self._stop_service_remove_dm_tables()

            UdevAdd._expected_stratis_block_devices(len(this_pool), devices)

            for d in this_pool:
                self._lb_mgr.unplug(d)

            UdevAdd._expected_stratis_block_devices(0, [])

            self._start_service()

        # Hot plug activate each pool in sequence and force a duplicate name
        # error.
        plugged = 0
        devices_plugged = []
        for i in range(num_pools):
            for d in pool_tokens[i]:
                self._lb_mgr.hotplug(d)
                plugged += 1
                devices_plugged.extend(self._device_files([d]))

            self._settle()
            UdevAdd._expected_stratis_block_devices(plugged, devices_plugged)

            # They all have the same name, so we should only get 1 pool!
            self.assertEqual(len(UdevAdd._get_pools()), 1)

        # Lets dynamically rename the active pools and then hot-plug the other
        # pools so that they all come up.  This simulates what an end user
        # could do to fix this condition until we have CLI support to assist.
        for _ in range(num_pools - 1):
            current_pools = UdevAdd._get_pools()

            existing_pool_count = len(current_pools)

            # Change the active pool name to be unique
            for p in current_pools:
                Pool.Methods.SetName(get_object(p[0]), {"name": rs(10)})

            # Generate synthetic add events
            for add_index in range(num_pools):
                for d in pool_tokens[add_index]:
                    self._lb_mgr.generate_udev_add_event(d)

            self._settle()
            UdevAdd._expected_stratis_block_devices(plugged, devices_plugged)
            self.assertEqual(len(UdevAdd._get_pools()),
                             existing_pool_count + 1)

        self.assertEqual(len(UdevAdd._get_pools()), num_pools)
Exemple #29
0
 def setUp(self):
     """
     Start the stratisd daemon with the simulator.
     """
     super().setUp()
     self._proxy = get_object(TOP_OBJECT)
Exemple #30
0
 def testExistingVolume(self):
     """
     The volume should be discovered.
     """
     get_volume(get_object(TOP_OBJECT), self._POOLNAME, self._VOLNAME)