[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
[rhel6-branch] Implement an option that lets anaconda name mpath devices by the wwid.
- From: Ales Kozumplik <akozumpl redhat com>
- To: anaconda-devel-list redhat com
- Subject: [rhel6-branch] Implement an option that lets anaconda name mpath devices by the wwid.
- Date: Thu, 16 Jun 2011 15:22:12 +0200
Adds a new option dialog to the filtering screen, with a checkbox. If user
unchecks this, /etc/multipath.conf is generated with user_friendly_names
set to "no". This will give all mpath devices names in the
/dev/mapper/<wwid> format, partitions are /dev/mapper<wwid>p1.
The setting defaults to using the friendly names.
Resolves: rhbz#709653
---
iw/filter_gui.py | 39 ++++++++++++----
kickstart.py | 2 +-
po/POTFILES.in | 1 +
storage/__init__.py | 9 +++-
storage/devicelibs/mpath.py | 8 ++--
storage/devicetree.py | 20 +++++----
tests/storage/devicelibs/mpath.py | 91 ++++++++++++++++++++++++++++++-------
ui/device-options.glade | 91 +++++++++++++++++++++++++++++++++++++
ui/filter.glade | 12 +++++
9 files changed, 229 insertions(+), 44 deletions(-)
mode change 100644 => 100755 tests/storage/devicelibs/mpath.py
create mode 100644 ui/device-options.glade
diff --git a/iw/filter_gui.py b/iw/filter_gui.py
index 63655a0..8717d6e 100644
--- a/iw/filter_gui.py
+++ b/iw/filter_gui.py
@@ -418,10 +418,20 @@ class FilterWindow(InstallWindow):
# are in the list.
selected = set()
for dev in self.pages[0].ds.getSelected():
- selected.add(udev_device_get_name(dev[OBJECT_COL]))
- if isMultipath(dev[OBJECT_COL]) or isRAID(dev[OBJECT_COL]):
+ info = dev[OBJECT_COL]
+ if isRAID(info):
+ selected.add(udev_device_get_name(info))
members = dev[MEMBERS_COL].split("\n")
selected.update(set(members))
+ if isMultipath(info):
+ if self.anaconda.id.storage.mpathFriendlyNames:
+ selected.add(udev_device_get_name(info))
+ else:
+ selected.add(dev[SERIAL_COL])
+ members = dev[MEMBERS_COL].split("\n")
+ selected.update(set(members))
+ else:
+ selected.add(udev_device_get_name(info))
if len(selected) == 0:
self.anaconda.intf.messageWindow(_("Error"),
@@ -446,10 +456,9 @@ class FilterWindow(InstallWindow):
udev_get_block_devices())
mcw = MultipathConfigWriter()
- cfg = mcw.write()
- open("/etc/multipath.conf", "w+").write(cfg)
- del cfg
- del mcw
+ cfg = mcw.write(friendly_names=True)
+ with open("/etc/multipath.conf", "w+") as mpath_cfg:
+ mpath_cfg.write(cfg)
(new_singlepaths, new_mpaths, new_partitions) = identifyMultipaths(new_disks)
(new_raids, new_nonraids) = self.split_list(lambda d: isRAID(d) and not isCCISS(d),
@@ -540,6 +549,15 @@ class FilterWindow(InstallWindow):
np.ds.addColumn(_("Device"), DEVICE_COL, displayed=False)
return np
+ def _options_clicked(self, button):
+ (xml, dialog) = gui.getGladeWidget("device-options.glade",
+ "options_dialog")
+ friendly_cb = xml.get_widget("mpath_friendly_names")
+ friendly_cb.set_active(self.anaconda.id.storage.mpathFriendlyNames)
+ if dialog.run() == gtk.RESPONSE_OK:
+ self.anaconda.id.storage.mpathFriendlyNames = friendly_cb.get_active()
+ dialog.destroy()
+
def _page_switched(self, notebook, useless, page_num):
# When the page is switched, we need to change what is visible so the
# Select All button only selects/deselected things on the current page.
@@ -558,9 +576,11 @@ class FilterWindow(InstallWindow):
self.buttonBox = self.xml.get_widget("buttonBox")
self.notebook = self.xml.get_widget("notebook")
self.addAdvanced = self.xml.get_widget("addAdvancedButton")
+ self.options = self.xml.get_widget("optionsButton")
self.notebook.connect("switch-page", self._page_switched)
self.addAdvanced.connect("clicked", self._add_advanced_clicked)
+ self.options.connect("clicked", self._options_clicked)
self.pages = []
@@ -600,10 +620,9 @@ class FilterWindow(InstallWindow):
udev_get_block_devices())
mcw = MultipathConfigWriter()
- cfg = mcw.write()
- open("/etc/multipath.conf", "w+").write(cfg)
- del cfg
- del mcw
+ cfg = mcw.write(friendly_names=True)
+ with open("/etc/multipath.conf", "w+") as mpath_cfg:
+ mpath_cfg.write(cfg)
if anaconda.isKickstart:
# identifyMultipaths() uses 'multipath -d' to find mpath devices. In
diff --git a/kickstart.py b/kickstart.py
index a4e25ac..61d00d3 100644
--- a/kickstart.py
+++ b/kickstart.py
@@ -184,7 +184,7 @@ def getEscrowCertificate(anaconda, url):
def detect_multipaths():
global multipaths
mcw = MultipathConfigWriter()
- cfg = mcw.write()
+ cfg = mcw.write(friendly_names=True)
with open("/etc/multipath.conf", "w+") as mpath_cfg:
mpath_cfg.write(cfg)
devices = udev_get_block_devices()
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 39a446b..6b8101d 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -158,6 +158,7 @@ ui/blwhere.glade.h
ui/cleardisks.glade.h
ui/create-storage.glade.h
ui/detailed-dialog.glade.h
+ui/device-options.glade.h
ui/fcoe-config.glade.h
ui/filter.glade.h
ui/iscsi-dialogs.glade.h
diff --git a/storage/__init__.py b/storage/__init__.py
index a7ff29b..007f029 100644
--- a/storage/__init__.py
+++ b/storage/__init__.py
@@ -309,6 +309,7 @@ class Storage(object):
self.protectedDevSpecs = []
self.autoPartitionRequests = []
self.eddDict = {}
+ self.mpathFriendlyNames = True
self.__luksDevs = {}
@@ -334,7 +335,8 @@ class Storage(object):
passphrase=self.encryptionPassphrase,
luksDict=self.__luksDevs,
iscsi=self.iscsi,
- dasd=self.dasd)
+ dasd=self.dasd,
+ mpathFriendlyNames=self.mpathFriendlyNames)
self.fsset = FSSet(self.devicetree, self.anaconda.rootPath)
self.services = set()
@@ -423,7 +425,8 @@ class Storage(object):
passphrase=self.encryptionPassphrase,
luksDict=self.__luksDevs,
iscsi=self.iscsi,
- dasd=self.dasd)
+ dasd=self.dasd,
+ mpathFriendlyNames=self.mpathFriendlyNames)
self.devicetree.populate()
self.fsset = FSSet(self.devicetree, self.anaconda.rootPath)
self.eddDict = get_edd_dict(self.partitioned)
@@ -2174,7 +2177,7 @@ class FSSet(object):
if multipath_conf:
multipath_path = os.path.normpath("%s/etc/multipath.conf" %
instPath)
- conf_contents = multipath_conf.write()
+ conf_contents = multipath_conf.write(self.devicetree.mpathFriendlyNames)
f = open(multipath_path, "w")
f.write(conf_contents)
f.close()
diff --git a/storage/devicelibs/mpath.py b/storage/devicelibs/mpath.py
index fb7e1aa..eb6e999 100644
--- a/storage/devicelibs/mpath.py
+++ b/storage/devicelibs/mpath.py
@@ -80,7 +80,7 @@ def parseMultipathOutput(output):
policy = re.compile('^[|+` -]+policy')
device = re.compile('^[|+` -]+[0-9]+:[0-9]+:[0-9]+:[0-9]+ +([a-zA-Z0-9!/]+)')
- create = re.compile('^(create: )?(mpath\w+)')
+ create = re.compile('^(create: )?(mpath\w+|[a-f0-9]+)')
lines = output.split('\n')
for line in lines:
@@ -236,7 +236,7 @@ class MultipathConfigWriter:
def addMultipathDevice(self, mpath):
self.mpaths.append(mpath)
- def write(self):
+ def write(self, friendly_names):
# if you add anything here, be sure and also add it to anaconda's
# multipath.conf
ret = ''
@@ -244,7 +244,7 @@ class MultipathConfigWriter:
# multipath.conf written by anaconda
defaults {
- user_friendly_names yes
+ user_friendly_names %(friendly_names)s
}
blacklist {
devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
@@ -273,7 +273,7 @@ blacklist {
device {
vendor "HPT"
}
-"""
+""" % {'friendly_names' : "yes" if friendly_names else "no"}
for device in self.blacklist_devices:
if device.serial:
ret += '\twwid "%s"\n' % device.serial
diff --git a/storage/devicetree.py b/storage/devicetree.py
index 0d48dda..b419026 100644
--- a/storage/devicetree.py
+++ b/storage/devicetree.py
@@ -153,7 +153,8 @@ class DeviceTree(object):
def __init__(self, intf=None, ignored=[], exclusive=[], type=CLEARPART_TYPE_NONE,
clear=[], zeroMbr=None, reinitializeDisks=None, protected=[],
- passphrase=None, luksDict=None, iscsi=None, dasd=None):
+ passphrase=None, luksDict=None, iscsi=None, dasd=None,
+ mpathFriendlyNames=True):
# internal data members
self._devices = []
self._actions = []
@@ -169,6 +170,7 @@ class DeviceTree(object):
self.reinitializeDisks = reinitializeDisks
self.iscsi = iscsi
self.dasd = dasd
+ self.mpathFriendlyNames = mpathFriendlyNames
# protected device specs as provided by the user
self.protectedDevSpecs = protected
@@ -1295,9 +1297,9 @@ class DeviceTree(object):
#
if udev_device_is_multipath_member(info) and device is None:
device = self.addUdevDiskDevice(info)
- elif udev_device_is_dm(info) and udev_device_is_dm_mpath(info):
+ elif udev_device_is_dm(info) and udev_device_is_dm_mpath(info) and device is None:
log.debug("%s is a multipath device" % name)
- self.addUdevDMDevice(info)
+ device = self.addUdevDMDevice(info)
elif udev_device_is_dm(info):
log.debug("%s is a device-mapper device" % name)
# try to look up the device
@@ -2057,9 +2059,9 @@ class DeviceTree(object):
% (livetarget,))
self.protectedDevNames.append(livetarget)
- cfg = self.__multipathConfigWriter.write()
- open("/etc/multipath.conf", "w+").write(cfg)
- del cfg
+ cfg = self.__multipathConfigWriter.write(self.mpathFriendlyNames)
+ with open("/etc/multipath.conf", "w+") as mpath_cfg:
+ mpath_cfg.write(cfg)
devices = udev_get_block_devices()
(singles, mpaths, partitions) = devicelibs.mpath.identifyMultipaths(devices)
@@ -2096,9 +2098,9 @@ class DeviceTree(object):
for d in self.devices:
if not d.name in whitelist:
self.__multipathConfigWriter.addBlacklistDevice(d)
- cfg = self.__multipathConfigWriter.write()
- open("/etc/multipath.conf", "w+").write(cfg)
- del cfg
+ cfg = self.__multipathConfigWriter.write(self.mpathFriendlyNames)
+ with open("/etc/multipath.conf", "w+") as mpath_cfg:
+ mpath_cfg.write(cfg)
# Now, loop and scan for devices that have appeared since the two above
# blocks or since previous iterations.
diff --git a/tests/storage/devicelibs/mpath.py b/tests/storage/devicelibs/mpath.py
old mode 100644
new mode 100755
index 8210b0b..f83ae3e
--- a/tests/storage/devicelibs/mpath.py
+++ b/tests/storage/devicelibs/mpath.py
@@ -1,13 +1,10 @@
-import baseclass
-import unittest
-import storage.devicelibs.mpath as mpath
-
-class MPathTestCase(baseclass.DevicelibsTestCase):
- def testMPath(self):
- ##
- ## parseMultipathOutput
- ##
- output="""\
+#!/usr/bin/python
+import mock
+
+class MPathTestCase(mock.TestCase):
+
+ # creating devices, user_friendly_names set to yes
+ output1 = """\
create: mpathb (1ATA ST3120026AS 5M) undef ATA,ST3120026AS
size=112G features='0' hwhandler='0' wp=undef
`-+- policy='round-robin 0' prio=1 status=undef
@@ -16,14 +13,74 @@ create: mpatha (36006016092d21800703762872c60db11) undef DGC,RAID 5
size=10G features='1 queue_if_no_path' hwhandler='1 emc' wp=undef
`-+- policy='round-robin 0' prio=2 status=undef
|- 6:0:0:0 sdb 8:16 undef ready running
- `- 7:0:0:0 sdc 8:32 undef ready running
+ `- 7:0:0:0 sdc 8:32 undef ready running\
+"""
+
+ # listing existing devices, user_friendly_names set to yes
+ output2 = """\
+mpathb (3600a0b800067fcc9000001f34d23ff88) dm-1 IBM,1726-4xx FAStT
+size=100G features='0' hwhandler='1 rdac' wp=rw
+`-+- policy='round-robin 0' prio=-1 status=active
+ |- 1:0:0:0 sda 8:0 active undef running
+ `- 2:0:0:0 sdc 8:32 active undef running
+mpatha (3600a0b800067fabc000067694d23fe6e) dm-0 IBM,1726-4xx FAStT
+size=100G features='0' hwhandler='1 rdac' wp=rw
+`-+- policy='round-robin 0' prio=-1 status=active
+ |- 1:0:0:1 sdb 8:16 active undef running
+ `- 2:0:0:1 sdd 8:48 active undef running
+"""
+
+ # creating devices, user_friendly_names set to no
+ output3 = """\
+create: 3600a0b800067fabc000067694d23fe6e undef IBM,1726-4xx FAStT
+size=100G features='1 queue_if_no_path' hwhandler='1 rdac' wp=undef
+`-+- policy='round-robin 0' prio=6 status=undef
+ |- 1:0:0:1 sdb 8:16 undef ready running
+ `- 2:0:0:1 sdd 8:48 undef ready running
+create: 3600a0b800067fcc9000001f34d23ff88 undef IBM,1726-4xx FAStT
+size=100G features='1 queue_if_no_path' hwhandler='1 rdac' wp=undef
+`-+- policy='round-robin 0' prio=3 status=undef
+ |- 1:0:0:0 sda 8:0 undef ready running
+ `- 2:0:0:0 sdc 8:32 undef ready running\
"""
- topology = mpath.parseMultipathOutput(output)
- expected = {'mpatha':['sdb','sdc'], 'mpathb':['sda']}
- self.assertEqual(topology, expected)
+
+ # listing existing devices, user_friendly_names set to no
+ output4 = """\
+3600a0b800067fcc9000001f34d23ff88 dm-1 IBM,1726-4xx FAStT
+size=100G features='0' hwhandler='1 rdac' wp=rw
+`-+- policy='round-robin 0' prio=-1 status=active
+ |- 1:0:0:0 sda 8:0 active undef running
+ `- 2:0:0:0 sdc 8:32 active undef running
+3600a0b800067fabc000067694d23fe6e dm-0 IBM,1726-4xx FAStT
+size=100G features='0' hwhandler='1 rdac' wp=rw
+`-+- policy='round-robin 0' prio=-1 status=active
+ |- 1:0:0:1 sdb 8:16 active undef running
+ `- 2:0:0:1 sdd 8:48 active undef running
+"""
+
+ def setUp(self):
+ self.setupModules(
+ ['_isys', 'logging', 'anaconda_log', 'block'])
+
+ def tearDown(self):
+ self.tearDownModules()
+
+ def testParse(self):
+ from storage.devicelibs import mpath
+ topology = mpath.parseMultipathOutput(self.output1)
+ self.assertEqual(topology,
+ {'mpatha':['sdb','sdc'], 'mpathb':['sda']})
+ topology = mpath.parseMultipathOutput(self.output2)
+ self.assertEqual(topology,
+ {'mpathb':['sda','sdc'], 'mpatha':['sdb', 'sdd']})
+ topology = mpath.parseMultipathOutput(self.output3)
+ self.assertEqual(topology,
+ {'3600a0b800067fabc000067694d23fe6e' : ['sdb','sdd'],
+ '3600a0b800067fcc9000001f34d23ff88' : ['sda', 'sdc']})
+ topology = mpath.parseMultipathOutput(self.output4)
+ self.assertEqual(topology,
+ {'3600a0b800067fabc000067694d23fe6e' : ['sdb','sdd'],
+ '3600a0b800067fcc9000001f34d23ff88' : ['sda', 'sdc']})
def suite():
return unittest.TestLoader().loadTestsFromTestCase(MPathTestCase)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/ui/device-options.glade b/ui/device-options.glade
new file mode 100644
index 0000000..7672f6e
--- /dev/null
+++ b/ui/device-options.glade
@@ -0,0 +1,91 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="options_dialog">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Device Options</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="cancelbutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="okbutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="mpath_friendly_names">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">If enabled the multipath devices are named following the /dev/mapper/mpath<letter> format instead of /dev/mapper/<wwid>.</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Use _friendly names for multipath devices</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/ui/filter.glade b/ui/filter.glade
index a2da183..54f141e 100644
--- a/ui/filter.glade
+++ b/ui/filter.glade
@@ -1264,6 +1264,18 @@ Target Identifier</property>
<property name="spacing">0</property>
<child>
+ <widget class="GtkButton" id="optionsButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Device Options</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
<widget class="GtkButton" id="addAdvancedButton">
<property name="visible">True</property>
<property name="can_default">True</property>
--
1.7.5.2
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]