[2.2-devel 1/1] Add a Format interface.
by dashea
From: David Lehman <dlehman(a)redhat.com>
---
blivet/dbus/blivet.py | 20 ++++++++++++++++
blivet/dbus/constants.py | 2 ++
blivet/dbus/device.py | 7 ++----
blivet/dbus/format.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++
tests/dbus_test.py | 16 ++++++++++++-
5 files changed, 101 insertions(+), 6 deletions(-)
create mode 100644 blivet/dbus/format.py
diff --git a/blivet/dbus/blivet.py b/blivet/dbus/blivet.py
index 96c1fa7..f92adca 100644
--- a/blivet/dbus/blivet.py
+++ b/blivet/dbus/blivet.py
@@ -26,6 +26,7 @@
from blivet.callbacks import callbacks
from .constants import BLIVET_INTERFACE, BLIVET_OBJECT_PATH, BUS_NAME
from .device import DBusDevice
+from .format import DBusFormat
from .object import DBusObject
@@ -38,6 +39,7 @@ class DBusBlivet(DBusObject):
def __init__(self, manager):
super().__init__()
self._dbus_devices = OrderedDict()
+ self._dbus_formats = OrderedDict()
self._manager = manager # provides ObjectManager interface
self._blivet = Blivet()
self._set_up_callbacks()
@@ -45,6 +47,8 @@ def __init__(self, manager):
def _set_up_callbacks(self):
callbacks.device_added.add(self._device_added)
callbacks.device_removed.add(self._device_removed)
+ callbacks.format_added.add(self._format_added)
+ callbacks.format_removed.add(self._format_removed)
@property
def object_path(self):
@@ -63,6 +67,11 @@ def _device_removed(self, device):
""" Update ObjectManager interface after a device is removed. """
removed_object_path = DBusDevice.get_object_path_by_id(device.id)
removed = self._dbus_devices[removed_object_path]
+ fmt_object_path = DBusFormat.get_object_path_by_id(device.format.id)
+ # Make sure the format gets removed in case the device was removed w/o
+ # removing the format first.
+ if fmt_object_path in self._dbus_formats:
+ self._format_removed(device.format)
self._manager.remove_object(removed)
del self._dbus_devices[removed_object_path]
@@ -72,6 +81,17 @@ def _device_added(self, device):
self._dbus_devices[added.object_path] = added
self._manager.add_object(added)
+ def _format_removed(self, fmt):
+ removed_object_path = DBusFormat.get_object_path_by_id(fmt.id)
+ removed = self._dbus_formats[removed_object_path]
+ self._manager.remove_object(removed)
+ del self._dbus_formats[removed_object_path]
+
+ def _format_added(self, fmt):
+ added = DBusFormat(fmt)
+ self._dbus_devices[added.object_path] = added
+ self._manager.add_object(added)
+
@dbus.service.method(dbus_interface=BLIVET_INTERFACE)
def Reset(self):
""" Reset the Blivet instance and populate the device tree. """
diff --git a/blivet/dbus/constants.py b/blivet/dbus/constants.py
index 8ba6f2f..d7c68da 100644
--- a/blivet/dbus/constants.py
+++ b/blivet/dbus/constants.py
@@ -24,6 +24,8 @@
BLIVET_OBJECT_PATH = "%s/Blivet" % BASE_OBJECT_PATH
DEVICE_INTERFACE = "%s.Device" % BUS_NAME
DEVICE_OBJECT_PATH_BASE = "%s/Devices" % BASE_OBJECT_PATH
+FORMAT_INTERFACE = "%s.Format" % BUS_NAME
+FORMAT_OBJECT_PATH_BASE = "%s/Formats" % BASE_OBJECT_PATH
OBJECT_MANAGER_PATH = BASE_OBJECT_PATH
OBJECT_MANAGER_INTERFACE = "org.freedesktop.DBus.ObjectManager"
diff --git a/blivet/dbus/device.py b/blivet/dbus/device.py
index e9ea330..e902ba4 100644
--- a/blivet/dbus/device.py
+++ b/blivet/dbus/device.py
@@ -20,6 +20,7 @@
import dbus
from .constants import DEVICE_INTERFACE, DEVICE_OBJECT_PATH_BASE
+from .format import DBusFormat
from .object import DBusObject
@@ -53,11 +54,7 @@ def properties(self):
"RaidLevel": self._get_raid_level(),
"Parents": dbus.Array((self.get_object_path_by_id(d.id) for d in self._device.parents), signature='o'),
"Children": dbus.Array((self.get_object_path_by_id(d.id) for d in self._device.children), signature='o'),
- "FormatType": self._device.format.type or "",
- "FormatUUID": self._device.format.uuid or "",
- "FormatMountpoint": getattr(self._device.format, "mountpoint", "") or "",
- "FormatLabel": getattr(self._device.format, "label", "") or "",
- "FormatID": self._device.format.id,
+ "Format": dbus.ObjectPath(DBusFormat.get_object_path_by_id(self._device.format.id))
}
return props
diff --git a/blivet/dbus/format.py b/blivet/dbus/format.py
new file mode 100644
index 0000000..18a0ebf
--- /dev/null
+++ b/blivet/dbus/format.py
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2016 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions of
+# the GNU General Public License v.2, or (at your option) any later version.
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY expressed or implied, including the implied warranties 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, write to the
+# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+# source code or documentation are not subject to the GNU General Public
+# License and may only be used or replicated with the express permission of
+# Red Hat, Inc.
+#
+# Red Hat Author(s): David Lehman <dlehman(a)redhat.com>
+#
+import dbus
+
+from .constants import FORMAT_INTERFACE, FORMAT_OBJECT_PATH_BASE
+from .object import DBusObject
+
+
+class DBusFormat(DBusObject):
+ def __init__(self, fmt):
+ self._format = fmt
+ self._object_path = self.get_object_path_by_id(self._format.id)
+ super().__init__()
+
+ @property
+ def object_path(self):
+ return self._object_path
+
+ @staticmethod
+ def get_object_path_by_id(object_id):
+ return "%s/%d" % (FORMAT_OBJECT_PATH_BASE, object_id)
+
+ @property
+ def interface(self):
+ return FORMAT_INTERFACE
+
+ @property
+ def properties(self):
+ props = {"Device": self._format.device,
+ "Type": self._format.type,
+ "ID": self._format.id,
+ "UUID": self._format.uuid or "",
+ "Label": getattr(self._format, "label", "") or "",
+ "Mountable": dbus.Boolean(self._format.mountable),
+ "Mountpoint": getattr(self._format, "mountpoint", "") or "",
+ "Status": dbus.Boolean(self._format.status)}
+ return props
+
+ @dbus.service.method(dbus_interface=FORMAT_INTERFACE, in_signature='a{sv}')
+ def Setup(self, kwargs):
+ self._format.setup(**kwargs)
+
+ @dbus.service.method(dbus_interface=FORMAT_INTERFACE)
+ def Teardown(self):
+ self._format.teardown()
diff --git a/tests/dbus_test.py b/tests/dbus_test.py
index 5c61840..e5f2b87 100644
--- a/tests/dbus_test.py
+++ b/tests/dbus_test.py
@@ -9,7 +9,7 @@
from blivet.dbus.blivet import DBusBlivet
from blivet.dbus.device import DBusDevice
from blivet.dbus.object import DBusObject
-from blivet.dbus.constants import BLIVET_INTERFACE, DEVICE_INTERFACE
+from blivet.dbus.constants import BLIVET_INTERFACE, DEVICE_INTERFACE, FORMAT_INTERFACE
class UDevBlivetTestCase(TestCase):
@@ -98,3 +98,17 @@ def test_properties(self, *args): # pylint: disable=unused-argument
self.assertEqual(self.obj.interface, DEVICE_INTERFACE)
self.assertEqual(self.obj.object_path,
self.obj.get_object_path_by_id(self._device_id))
+
+
+class DBusFormatTestCase(DBusObjectTestCase):
+ @patch.object(DBusObject, '__init__', return_value=None)
+ @patch("blivet.dbus.blivet.callbacks")
+ def setUp(self, *args):
+ self._format_id = random.randint(0, 500)
+ self.obj = DBusFormat(Mock(name="DeviceFormat", id=self._device_id))
+
+ def test_properties(self, *args): # pylint: disable=unused-argument
+ self.assertTrue(isinstance(self.obj.properties, dict))
+ self.assertEqual(self.obj.interface, FORMAT_INTERFACE)
+ self.assertEqual(self.obj.object_path,
+ self.obj.get_object_path_by_id(self._format_id))
--
To view this commit on github, visit https://github.com/rhinstaller/blivet/commit/7d759354447796d8ad7ce9f1f6d0...
7 years, 11 months
[PATCH rhel7-branch] network: validate netmask in tui (#1331054)
by Radek Vykydal
Resolves: rhbz#1331054
---
pyanaconda/regexes.py | 3 ++
pyanaconda/ui/tui/spokes/network.py | 12 +++++--
tests/regex_tests/netmask_test.py | 69 +++++++++++++++++++++++++++++++++++++
3 files changed, 81 insertions(+), 3 deletions(-)
create mode 100644 tests/regex_tests/netmask_test.py
diff --git a/pyanaconda/regexes.py b/pyanaconda/regexes.py
index 2235d89..b99670b 100644
--- a/pyanaconda/regexes.py
+++ b/pyanaconda/regexes.py
@@ -89,6 +89,9 @@ IPV6_PATTERN_WITHOUT_ANCHORS = r'(?:' + \
r'(?:(?:(?:[0-9a-fA-F]{1,4}:){,6}(?:[0-9a-fA-F]{1,4}))?::)' + \
r')'
+# IPv4 dotted-quad netmask validation
+IPV4_NETMASK_WITHOUT_ANCHORS = r'((128|192|224|240|248|252|254)\.0\.0\.0)|(255\.(((0|128|192|224|240|248|252|254)\.0\.0)|(255\.(((0|128|192|224|240|248|252|254)\.0)|255\.(0|128|192|224|240|248|252|254)))))'
+
# Hostname validation
# A hostname consists of sections separated by periods. Each of these sections
# must be between 1 and 63 characters, contain only alphanumeric characters or
diff --git a/pyanaconda/ui/tui/spokes/network.py b/pyanaconda/ui/tui/spokes/network.py
index 131a92a..8701598 100644
--- a/pyanaconda/ui/tui/spokes/network.py
+++ b/pyanaconda/ui/tui/spokes/network.py
@@ -30,7 +30,7 @@ from pyanaconda.i18n import N_, _
from pyanaconda import network
from pyanaconda import nm
-from pyanaconda.regexes import IPV4_PATTERN_WITHOUT_ANCHORS
+from pyanaconda.regexes import IPV4_PATTERN_WITHOUT_ANCHORS, IPV4_NETMASK_WITHOUT_ANCHORS
from pyanaconda.constants_text import INPUT_PROCESSED
import logging
@@ -304,7 +304,7 @@ class ConfigureNetworkSpoke(EditTUISpoke):
edit_fields = [
Entry(N_('IPv4 address or %s for DHCP') % '"dhcp"', "ip",
re.compile("^(?:" + IPV4_PATTERN_WITHOUT_ANCHORS + "|dhcp)$"), True),
- Entry(N_("IPv4 netmask"), "netmask", re.compile("^" + IPV4_PATTERN_WITHOUT_ANCHORS + "$"), True),
+ Entry(N_("IPv4 netmask"), "netmask", re.compile("^" + IPV4_NETMASK_WITHOUT_ANCHORS + "$"), True),
Entry(N_("IPv4 gateway"), "gateway", re.compile("^" + IPV4_PATTERN_WITHOUT_ANCHORS + "$"), True),
Entry(N_('IPv6 address or %(auto)s for automatic, %(dhcp)s for DHCP, %(ignore)s to turn off')
% {"auto": '"auto"', "dhcp": '"dhcp"', "ignore": '"ignore"'}, "ipv6",
@@ -324,7 +324,6 @@ class ConfigureNetworkSpoke(EditTUISpoke):
if self.args.noipv6:
self.args.ipv6 = "ignore"
self.args._apply = False
- self.dialog.wrong_input_message = _("Bad format of the IP address")
def refresh(self, args=None):
""" Refresh window. """
@@ -333,6 +332,13 @@ class ConfigureNetworkSpoke(EditTUISpoke):
self._window += [TextWidget(message), ""]
return True
+ def input(self, args, key):
+ if self.edit_fields[int(key)-1].attribute == "netmask":
+ self.dialog.wrong_input_message = _("Bad format of the netmask")
+ else:
+ self.dialog.wrong_input_message = _("Bad format of the IP address")
+ return EditTUISpoke.input(self, args, key)
+
@property
def indirect(self):
return True
diff --git a/tests/regex_tests/netmask_test.py b/tests/regex_tests/netmask_test.py
new file mode 100644
index 0000000..c166636
--- /dev/null
+++ b/tests/regex_tests/netmask_test.py
@@ -0,0 +1,69 @@
+#!/usr/bin/python
+# vim:set fileencoding=utf-8
+#
+# Copyright (C) 2014 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions of
+# the GNU General Public License v.2, or (at your option) any later version.
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY expressed or implied, including the implied warranties 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, write to the
+# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+# source code or documentation are not subject to the GNU General Public
+# License and may only be used or replicated with the express permission of
+# Red Hat, Inc.
+#
+# Red Hat Author(s): Radek Vykydal <rvykydal(a)redhat.com>
+#
+import unittest
+import re
+
+from pyanaconda.regexes import IPV4_NETMASK_WITHOUT_ANCHORS
+
+def _run_tests(testcase, expression, goodlist, badlist):
+ got_error = False
+ for good in goodlist:
+ try:
+ testcase.assertIsNotNone(expression.match(good))
+ except AssertionError:
+ got_error = True
+ print("Good string %s did not match expression" % good)
+
+ for bad in badlist:
+ try:
+ testcase.assertIsNone(expression.match(bad))
+ except AssertionError:
+ got_error = True
+ print("Bad string %s matched expression" % bad)
+
+ if got_error:
+ testcase.fail()
+
+class IPv4NetmaskTestCase(unittest.TestCase):
+ def netmask_test(self):
+ good_tests = [
+ '255.255.255.0',
+ '255.255.0.0',
+ '255.255.255.254',
+ '128.0.0.0',
+ ]
+
+ bad_tests = [
+ '255.254.255.0',
+ '24',
+ '255',
+ '255.0',
+ '255.255.0',
+ '192.168.1.1',
+ '256.0.0.0'
+ '255.b.255.0',
+ '...',
+ '255...'
+ ]
+
+ netmask_re = re.compile('^(' + IPV4_NETMASK_WITHOUT_ANCHORS + ')$')
+ _run_tests(self, netmask_re, good_tests, bad_tests)
--
2.4.3
7 years, 11 months
Re: [rhinstaller/blivet/pulls/399 2.0-devel] Size tests fix
by dashea
Wow, how did I not notice that libbytesize doesn't use `ROUND_HALF_UP` (or even support it)?
My brain struggles mightily with the idea that `round_to_nearest('10.3')` would return `11` as opposed to `10` given that `10.3` is more than _twice_ as close to `10` than to `11`.
Since we are dealing with size quantities here I can see an argument for rounding up in certain situations, but it is still a mental hurdle for me. If the size represents a quantity used, rounding up seems to make sense (so that we do not under-estimate how much we have taken). But what if the size represents a quantity of free space? Rounding up seems to be a bad idea for this (because it leads us to over-estimate how much we have available). And what if we're relating two complementary sizes? `ROUND_HALF_UP` makes those kinds of relations sensible in general even when rounding.
Consider a `100 GiB` drive with a `44.2 GiB` partition and `55.8 GiB` of free space. If someone wanted to get a general feel for the situation, for example to display in a UI, here's what we'd see:
With `ROUND_UP`:
```
Disk Size: 100 GiB
Used: 45 GiB
Free: 56 GiB
```
With `ROUND_HALF_UP`:
```
Disk Size: 100 GiB
Used: 44 GiB
Free: 56 GiB
```
Which one do you think does a better job of representing the truth?
--
To view this pull request on github, visit https://github.com/rhinstaller/blivet/pull/399
7 years, 11 months
Re: [rhinstaller/blivet/pulls/399 2.0-devel] Size tests fix
by dashea
Wow, how did I not notice that libbytesize doesn't use `ROUND_HALF_UP` (or even support it)?
My brain struggles mightily with the idea that `round_to_nearest('10.3')` would return `11` as opposed to `10` given that `10.3` is more than _twice_ as close to `10` as it is to `11`.
Since we are dealing with size quantities here I can see an argument for rounding up in certain situations, but it is still a mental hurdle for me. If the size represents a quantity used, rounding up seems to make sense (so that we do not under-estimate how much we have taken). But what if the size represents a quantity of free space? Rounding up seems to be a bad idea for this (because it leads us to over-estimate how much we have available). And what if we're relating two complementary sizes? `ROUND_HALF_UP` makes those kinds of relations sensible in general even when rounding.
Consider a `100 GiB` drive with a `44.2 GiB` partition and `55.8 GiB` of free space. If someone wanted to get a general feel for the situation, for example to display in a UI, here's what we'd see:
With `ROUND_UP`:
```
Disk Size: 100 GiB
Used: 45 GiB
Free: 56 GiB
```
With `ROUND_HALF_UP`:
```
Disk Size: 100 GiB
Used: 44 GiB
Free: 56 GiB
```
Which one do you think does a better job of representing the truth?
--
To view this pull request on github, visit https://github.com/rhinstaller/blivet/pull/399
7 years, 11 months