Пример #1
0
    def list_pools(_):
        """
        List all stratis pools.

        :raises StratisCliEngineError:
        """
        # pylint: disable=import-outside-toplevel
        from ._data import MOPool
        from ._data import ObjectManager
        from ._data import pools

        proxy = get_object(TOP_OBJECT)

        managed_objects = ObjectManager.Methods.GetManagedObjects(proxy, {})
        mopools = (MOPool(info) for _, info in pools().search(managed_objects))
        tables = [[
            mopool.Name(),
            str(Range(mopool.TotalPhysicalSize(), SECTOR_SIZE)),
            str(Range(mopool.TotalPhysicalUsed(), SECTOR_SIZE)),
        ] for mopool in mopools]
        print_table(
            ["Name", "Total Physical Size", "Total Physical Used"],
            sorted(tables, key=lambda entry: entry[0]),
            ["<", ">", ">"],
        )
Пример #2
0
def _possibly_add_filesystems(pool_object_path, *, fs_specs=None):
    """
    Add filesystems to the already created pool to set up testing, if
    filesystms have been specified.

    :param str pool_object_path: the D-Bus object path
    :param fs_specs: the filesystem specs
    :type fs_specs: list of str * Range or NoneType

    :returns: the change in size of pool's TotalPhysicalUsed value
    :rtype: Range
    """
    if fs_specs is not None:
        pool_proxy = get_object(pool_object_path)

        (real, pool_used_pre) = Pool.Properties.TotalPhysicalUsed.Get(pool_proxy)
        if not real:
            raise RuntimeError("Failed to get pool usage before creating filesystems.")

        (_, return_code, message,) = Pool.Methods.CreateFilesystems(
            pool_proxy,
            {"specs": map(lambda x: (x[0], (True, str(x[1].magnitude))), fs_specs)},
        )

        if return_code != 0:
            raise RuntimeError("Failed to create a requested filesystem: %s" % message)

        (real, pool_used_post) = Pool.Properties.TotalPhysicalUsed.Get(pool_proxy)
        if not real:
            raise RuntimeError("Failed to get pool usage after creating filesystems.")

        return Range(pool_used_post) - Range(pool_used_pre)

    return Range(0)
Пример #3
0
    def _check_prediction(self, prediction, mopool):
        """
        Check the prediction against the values obtained from the D-Bus.

        :param str prediction: result of calling script, JSON format
        :param MOPool mopool: object with pool properties
        """
        encrypted = mopool.Encrypted()

        (success, total_physical_used) = mopool.TotalPhysicalUsed()
        if not success:
            raise RuntimeError("Pool's TotalPhysicalUsed property was invalid.")

        (used_prediction, total_prediction) = (
            prediction["used"],
            prediction["total"],
        )

        if encrypted:
            self.assertLess(mopool.TotalPhysicalSize(), total_prediction)
            self.assertLess(total_physical_used, used_prediction)

            diff1 = Range(total_prediction) - Range(mopool.TotalPhysicalSize())
            diff2 = Range(used_prediction) - Range(total_physical_used)

            self.assertEqual(diff1, diff2)
        else:
            self.assertEqual(mopool.TotalPhysicalSize(), total_prediction)
            self.assertEqual(total_physical_used, used_prediction)
Пример #4
0
    def test_prediction(self):
        """
        Verify that the prediction of space used by the filesystem subcommand
        is the same as the prediction obtained by computing over the results
        obtained by calling the pool subcommand with different arguments and
        taking the difference.
        """
        encrypted = False
        overprovisioned = True
        device_sizes = [Range(1, TiB)]
        fs_sizes = [Range(1, GiB)]

        pool_result_pre = _call_predict_usage_pool(
            encrypted, device_sizes, fs_sizes=None, overprovision=overprovisioned
        )
        pool_result_post = _call_predict_usage_pool(
            encrypted,
            device_sizes,
            fs_sizes=fs_sizes,
            overprovision=overprovisioned,
        )

        filesystem_result = _call_predict_usage_filesystem(
            fs_sizes, overprovision=overprovisioned
        )

        self.assertEqual(
            Range(pool_result_post["used"]) - Range(pool_result_pre["used"]),
            Range(filesystem_result["used"]),
        )
Пример #5
0
    def _check_fs_prediction(
        self, pre_prediction, post_prediction, change, *, overprovision=True
    ):
        """
        Check the prediction for filesystems by comparing a prediction
        before filesystems are added to one after filesystems are added.

        It should be greater or equal to the actual change but no greater than
        a statical limit times the actual change.

        :param str pre_prediction: prediction before filesystems
        :param str post_prediction: prediction after filesystems
        :param Range change: the real change in TotalPhysicalUsed result
        :param bool overprovision: whether overprovisioning is allowed on pool
        """
        pre_used = Range(pre_prediction["used"])
        post_used = Range(post_prediction["used"])

        prediction_change = post_used - pre_used

        if overprovision:
            self.assertGreaterEqual(prediction_change, change)
            self.assertLessEqual(prediction_change, _FILESYSTEM_MULT_LIMIT * change)
        else:
            # If no overprovisioning is allowed, the prediction will exceed the
            # actual used for any filesystem.
            self.assertLess(change, prediction_change)
Пример #6
0
 def testExceptions(self):
     """ Test raising exceptions when rounding. """
     with self.assertRaises(RangeValueError):
         Range(0).roundTo(Range(-1, B), rounding=ROUND_HALF_UP)
     with self.assertRaises(RangeValueError):
         Range(512).roundTo(1.4, rounding=ROUND_HALF_UP)
     with self.assertRaises(RangeValueError):
         s = Range(512)
         s.roundTo(512, rounding=ROUND_HALF_UP, bounds=(Range(0), Range(-1)))
Пример #7
0
 def list_pool(namespace):
     """
     List devices in a pool.
     """
     proxy = get_object(TOP_OBJECT)
     managed_objects = ObjectManager.Methods.GetManagedObjects(proxy, {})
     (parent_pool_object_path, _) = unique(
         pools(props={
             'Name': namespace.pool_name
         }).search(managed_objects))
     modevs = [
         MODev(info) for _, info in devs(props={
             "Pool": parent_pool_object_path
         }, ).search(managed_objects)
     ]
     tables = [[
         modev.Devnode(),
         str(Range(modev.TotalPhysicalSize(), SECTOR_SIZE)),
         state_val_to_string(modev.State()),
         tier_val_to_string(modev.Tier()),
     ] for modev in modevs]
     print_table([
         "Device Node",
         "Physical Size",
         "State",
         "Tier",
     ], sorted(tables, key=lambda entry: entry[0]), ['<', '>', '>', '>'])
Пример #8
0
    def list_volumes(namespace):
        """
        List the volumes in a pool.
        """
        # pylint: disable=import-outside-toplevel
        from ._data import MOFilesystem
        from ._data import MOPool
        from ._data import ObjectManager
        from ._data import filesystems
        from ._data import pools

        # This method is invoked as the default for "stratis filesystem";
        # the namespace may not have a pool_name field.
        pool_name = getattr(namespace, "pool_name", None)

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

        mofilesystems = (
            MOFilesystem(info)
            for _, info in filesystems(
                props=None
                if pool_name is None
                else {
                    "Pool": next(
                        pools(props={"Name": pool_name})
                        .require_unique_match(True)
                        .search(managed_objects)
                    )[0]
                }
            ).search(managed_objects)
        )

        path_to_name = dict(
            (path, MOPool(info).Name())
            for path, info in pools(
                props=None if pool_name is None else {"Name": pool_name}
            ).search(managed_objects)
        )

        tables = [
            [
                path_to_name[mofilesystem.Pool()],
                mofilesystem.Name(),
                str(Range(mofilesystem.Used())),
                date_parser.parse(mofilesystem.Created())
                .astimezone()
                .strftime("%b %d %Y %H:%M"),
                mofilesystem.Devnode(),
                mofilesystem.Uuid(),
            ]
            for mofilesystem in mofilesystems
        ]

        print_table(
            ["Pool Name", "Name", "Used", "Created", "Device", "UUID"],
            sorted(tables, key=lambda entry: entry[0]),
            ["<", "<", "<", "<", "<", "<"],
        )
Пример #9
0
    def list_pools(_):
        """
        List all stratis pools.

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

        managed_objects = ObjectManager.Methods.GetManagedObjects(proxy, {})
        mopools = (MOPool(info) for _, info in pools().search(managed_objects))
        tables = [[
            mopool.Name(),
            str(Range(mopool.TotalPhysicalSize(), SECTOR_SIZE)),
            str(Range(mopool.TotalPhysicalUsed(), SECTOR_SIZE)),
        ] for mopool in mopools]
        print_table(['Name', 'Total Physical Size', 'Total Physical Used'],
                    sorted(tables, key=lambda entry: entry[0]),
                    ['<', '>', '>'])
Пример #10
0
        def filesystem_size_triple(dbus_props):
            """
            Calcuate the triple to display for filesystem size.

            :param dbus_props: filesystem D-Bus properties
            :type dbus_props: MOFilesystem

            :returns: a string a formatted string showing all three values
            :rtype: str
            """
            total = Range(dbus_props.Size())
            used = get_property(dbus_props.Used(), Range, None)
            return size_triple(total, used)
Пример #11
0
    def test_prediction_filesystems(self):
        """
        Verify that the prediction of space used is within acceptable limits
        when creating filesystems.
        """
        device_tokens = self._lb_mgr.create_devices(4)
        devnodes = self._lb_mgr.device_files(device_tokens)

        with ServiceContextManager():
            pool_name = random_string(5)
            create_pool(pool_name, devnodes)
            self.wait_for_pools(1)
            self._test_prediction(pool_name, fs_specs=[("fs1", Range(1, TiB))])
Пример #12
0
        def filesystem_used(props):
            """
            Calculate the string value to display for filesystem used.

            The format is just that chosen by justbytes default configuration.

            :param props: a dictionary of property values obtained
            :type props: a dict of str * object
            :returns: a string to display in the resulting list output
            :rtype: str
            """
            return get_property(props, "Used", lambda x: str(Range(x)),
                                TABLE_FAILURE_STRING)
Пример #13
0
    def test_prediction_no_overprov(self):
        """
        Verify that the prediction of space used is within acceptable limits
        when no overprovisioning is allowed.
        """
        device_tokens = self._lb_mgr.create_devices(4)
        devnodes = self._lb_mgr.device_files(device_tokens)

        with ServiceContextManager():
            pool_name = random_string(5)
            create_pool(pool_name, devnodes, overprovision=False)
            self.wait_for_pools(1)
            self._test_prediction(
                pool_name, fs_specs=[("fs1", Range(2, GiB))], overprovision=False
            )
Пример #14
0
    def __call__(self, parser, namespace, values, option_string=None):
        """
        Set dest namespace attribute to Range value parsed from values.
        """
        match = _RANGE_RE.search(values)
        if match is None:
            raise argparse.ArgumentError(
                self,
                "Ill-formed size specification: %s" % _SIZE_SPECIFICATION)

        (magnitude, unit) = (match.group("magnitude"), match.group("units"))

        units = _unit_map(unit)

        size = Range(magnitude, units)

        setattr(namespace, self.dest, size)
Пример #15
0
    def list_devices(namespace):
        """
        List devices. If a pool is specified in the namespace, list devices
        for that pool. Otherwise, list all devices for all pools.
        """
        # pylint: disable=import-outside-toplevel
        from ._data import devs
        from ._data import pools
        from ._data import MODev
        from ._data import MOPool
        from ._data import ObjectManager

        # This method is invoked as the default for "stratis blockdev";
        # the namespace may not have a pool_name field.
        pool_name = getattr(namespace, "pool_name", None)

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

        modevs = (MODev(info) for _, info in devs(
            props=None if pool_name is None else {
                "Pool":
                next(
                    pools(props={
                        "Name": pool_name
                    }).require_unique_match(True).search(managed_objects))[0]
            }).search(managed_objects))

        path_to_name = dict(
            (path, MOPool(info).Name())
            for path, info in pools(props=None if pool_name is None else {
                "Name": pool_name
            }).search(managed_objects))

        tables = [[
            path_to_name[modev.Pool()],
            modev.Devnode(),
            str(Range(modev.TotalPhysicalSize(), SECTOR_SIZE)),
            BLOCK_DEV_STATE_TO_NAME(modev.State(), True),
            BLOCK_DEV_TIER_TO_NAME(modev.Tier(), True),
        ] for modev in modevs]
        print_table(
            ["Pool Name", "Device Node", "Physical Size", "State", "Tier"],
            sorted(tables, key=lambda entry: (entry[0], entry[1])),
            ["<", "<", ">", ">", ">"],
        )
Пример #16
0
        def physical_size_triple(mopool):
            """
            Calculate the triple to display for total physical size.

            The format is total/used/free where the display value for each
            member of the tuple are chosen automatically according to justbytes'
            configuration.

            :param mopool: an object representing all the properties of the pool
            :type mopool: MOPool
            :returns: a string to display in the resulting list output
            :rtype: str
            """
            total_physical_size = Range(mopool.TotalPhysicalSize())
            total_physical_used = get_property(mopool.TotalPhysicalUsed(),
                                               Range, None)
            return size_triple(total_physical_size, total_physical_used)
Пример #17
0
        def total_physical_size(props):
            """
            Calculate the string value to display for physical size of block
            device.

            The format is just that chosen by justbytes default configuration.

            :param props: a dictionary of property values obtained
            :type props: a dict of str * object
            :returns: a string to display in the resulting list output
            :rtype: str
            """
            return get_property(
                props,
                "TotalPhysicalSize",
                lambda x: str(Range(x)),
                TABLE_FAILURE_STRING,
            )
Пример #18
0
    def list_pool(namespace):
        """
        List devices. If a pool is specified in the namespace, list devices
        for that pool. Otherwise, list all devices for all pools.
        """
        proxy = get_object(TOP_OBJECT)
        managed_objects = ObjectManager.Methods.GetManagedObjects(proxy, {})

        (modevs, path_to_name) = get_objects(namespace, "pool_name",
                                             managed_objects, devs, MODev)

        tables = [[
            path_to_name[modev.Pool()],
            modev.Devnode(),
            str(Range(modev.TotalPhysicalSize(), SECTOR_SIZE)),
            BLOCK_DEV_STATE_TO_NAME(modev.State(), True),
            BLOCK_DEV_TIER_TO_NAME(modev.Tier(), True)
        ] for modev in modevs]
        print_table(
            ["Pool Name", "Device Node", "Physical Size", "State", "Tier"],
            sorted(tables, key=lambda entry: (entry[0], entry[1])),
            ['<', '<', '>', '>', '>'])
Пример #19
0
    def list_volumes(namespace):
        """
        List the volumes in a pool.
        """
        proxy = get_object(TOP_OBJECT)
        managed_objects = ObjectManager.Methods.GetManagedObjects(proxy, {})

        (mofilesystems, path_to_name) = get_objects(namespace, "pool_name",
                                                    managed_objects,
                                                    filesystems, MOFilesystem)

        tables = [[
            path_to_name[mofilesystem.Pool()],
            mofilesystem.Name(),
            str(Range(mofilesystem.Used())),
            date_parser.parse(mofilesystem.Created()).astimezone().strftime(
                "%b %d %Y %H:%M"),
            mofilesystem.Devnode(),
            mofilesystem.Uuid(),
        ] for mofilesystem in mofilesystems]

        print_table(['Pool Name', 'Name', 'Used', 'Created', 'Device', 'UUID'],
                    sorted(tables, key=lambda entry: entry[0]),
                    ['<', '<', '<', '<', '<', '<'])
Пример #20
0
 def testExceptionValues(self):
     """ Test that exceptions are properly raised on bad params. """
     s = Range(500)
     with self.assertRaises(RangeValueError):
         s.components(ValueConfig(min_value=-1))
Пример #21
0
 def testRoundingToBytes(self):
     """ Test that second part is B when rounding to bytes. """
     s = Range(500)
     self.assertEqual(s.components()[1], B)
Пример #22
0
 def testSIUnits(self):
     """ Test binary_units param. """
     s = Range(1000)
     self.assertEqual(s.components(ValueConfig(binary_units=False)), (1, KB))
Пример #23
0
    def list_devices(namespace):
        """
        List devices. If a pool is specified in the namespace, list devices
        for that pool. Otherwise, list all devices for all pools.
        """
        # pylint: disable=import-outside-toplevel
        from ._data import MODev, MOPool, ObjectManager, devs, pools

        # This method is invoked as the default for "stratis blockdev";
        # the namespace may not have a pool_name field.
        pool_name = getattr(namespace, "pool_name", None)

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

        modevs = [
            MODev(info)
            for objpath, info in devs(
                props=None
                if pool_name is None
                else {
                    "Pool": next(
                        pools(props={"Name": pool_name})
                        .require_unique_match(True)
                        .search(managed_objects)
                    )[0]
                }
            ).search(managed_objects)
        ]

        path_to_name = dict(
            (path, MOPool(info).Name())
            for path, info in pools(
                props=None if pool_name is None else {"Name": pool_name}
            ).search(managed_objects)
        )

        def paths(modev):
            """
            Return <physical_path> (<metadata_path>) if they are different,
            otherwise, just <metadata_path>.

            physical_path D-Bus Property key is PhysicalPath
            metadata_path D-Bus Property key is Devnode

            :param modev: object containing D-Bus properties
            :returns: the string to print
            :rtype: str
            """
            metadata_path = modev.Devnode()
            physical_path = modev.PhysicalPath()

            return (
                metadata_path
                if metadata_path == physical_path
                else "%s (%s)" % (physical_path, metadata_path)
            )

        tables = [
            [
                path_to_name[modev.Pool()],
                paths(modev),
                str(Range(modev.TotalPhysicalSize())),
                BLOCK_DEV_TIER_TO_NAME(modev.Tier(), True),
            ]
            for modev in modevs
        ]
        print_table(
            ["Pool Name", "Device Node", "Physical Size", "Tier"],
            sorted(tables, key=lambda entry: (entry[0], entry[1])),
            ["<", "<", ">", ">"],
        )
Пример #24
0
 def testNegative(self):
     """ Test construction of negative sizes. """
     s = Range(-500, MiB)
     self.assertEqual(s.components(), (Fraction(-500, 1), MiB))
     self.assertEqual(s.convertTo(B), -524288000)
Пример #25
0
    def testMinValue(self):
        """ Test behavior on min_value parameter. """
        s = Range(9, MiB)
        self.assertEqual(s.components(), (Fraction(9, 1), MiB))
        self.assertEqual(
           s.components(ValueConfig(min_value=10)),
           (Fraction(9216, 1), KiB)
        )

        s = Range("0.5", GiB)
        self.assertEqual(
           s.components(ValueConfig(min_value=1)),
           (Fraction(512, 1), MiB)
        )
        self.assertEqual(
           s.components(ValueConfig(min_value=Fraction(1, 10))),
           (Fraction(1, 2), GiB)
        )
        self.assertEqual(
           s.components(ValueConfig(min_value=1)),
           (Fraction(512, 1), MiB)
        )

        # when min_value is 10 and single digit on left of decimal, display
        # with smaller unit.
        s = Range('7.18', KiB)
        self.assertEqual(s.components(ValueConfig(min_value=10))[1], B)
        s = Range('9.68', TiB)
        self.assertEqual(s.components(ValueConfig(min_value=10))[1], GiB)
        s = Range('4.29', MiB)
        self.assertEqual(s.components(ValueConfig(min_value=10))[1], KiB)

        # when min value is 100 and two digits on left of decimal
        s = Range('14', MiB)
        self.assertEqual(
           s.components(ValueConfig(min_value=100)),
           (Fraction(14 * 1024, 1), KiB)
        )