This patch adds support for using FCoE during the installation. This patch merely lays the initial ground work, there is more work todo: - The system will not boot without manual help after the install, as dracut / mkinitrd do not support FCoE yet - If FCoE is not used for / but for example for /srv, then information about the nic used for FCoE needs to be written in a to be defined config file in the system, and rc.sysinit needs to be thought to read this file and bring up FCoE SAN's / Fabrics not used for / - kickstart support for FCoE still needs to be done --- iw/autopart_type.py | 84 ++++++++++++++++++++++++++- storage/__init__.py | 5 ++ storage/fcoe.py | 92 +++++++++++++++++++++++++++++ textw/partition_text.py | 29 +++++++++- ui/adddrive.glade | 19 ++++++ ui/fcoe-config.glade | 149 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 376 insertions(+), 2 deletions(-) create mode 100644 storage/fcoe.py create mode 100644 ui/fcoe-config.glade diff --git a/iw/autopart_type.py b/iw/autopart_type.py index 8a12689..9c04e52 100644 --- a/iw/autopart_type.py +++ b/iw/autopart_type.py @@ -32,6 +32,7 @@ from iw_gui import * from flags import flags import network from storage import iscsi +from storage import fcoe from storage.deviceaction import * import gettext @@ -325,6 +326,81 @@ class PartitionTypeWindow(InstallWindow): return rc + def addFcoeDrive(self): + (dxml, dialog) = gui.getGladeWidget("fcoe-config.glade", + "fcoeDialog") + + # Populate the combo + combo = dxml.get_widget("fcoeNicCombo") + cell = gtk.CellRendererText() + combo.pack_start(cell, True) + combo.set_attributes(cell, text = 0) + cell.set_property("wrap-width", 525) + combo.set_size_request(480, -1) + store = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING) + combo.set_model(store) + + netdevs = self.anaconda.id.network.available() + keys = netdevs.keys() + keys.sort() + selected_interface = None + for dev in keys: + # Skip NIC's which are connected (iow in use for a net install) + if dev in network.getActiveNetDevs(): + continue + + i = store.append(None) + + desc = netdevs[dev].get("DESC") + if desc: + desc = "%s - %s" %(dev, desc) + else: + desc = "%s" %(dev,) + + mac = netdevs[dev].get("HWADDR") + if mac: + desc = "%s - %s" %(desc, mac) + + if selected_interface is None: + selected_interface = i + + store[i] = (desc, dev) + + if selected_interface: + combo.set_active_iter(selected_interface) + else: + combo.set_active(0) + + # Show the dialog + gui.addFrame(dialog) + dialog.show_all() + sg = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + sg.add_widget(dxml.get_widget("fcoeNicCombo")) + + while 1: + rc = dialog.run() + + if rc == gtk.RESPONSE_CANCEL: + break; + + iter = combo.get_active_iter() + if iter is None: + self.intf.messageWindow(_("Error"), + "Must select a NIC to use.", + type="warning", custom_icon="error") + continue; + + try: + self.storage.fcoe.addSan(store.get_value(iter, 1), self.intf) + except IOError, e: + self.intf.messageWindow(_("Error"), str(e)) + rc = gtk.RESPONSE_CANCEL + + break + + dialog.destroy() + return rc + def addZfcpDrive(self): (dxml, dialog) = gui.getGladeWidget("zfcp-config.glade", "zfcpDialog") @@ -366,6 +442,10 @@ class PartitionTypeWindow(InstallWindow): dxml.get_widget("iscsiRadio").set_sensitive(False) dxml.get_widget("iscsiRadio").set_active(False) + if not fcoe.has_fcoe(): + dxml.get_widget("fcoeRadio").set_sensitive(False) + dxml.get_widget("fcoeRadio").set_active(False) + #figure out what advanced devices we have available and set sensible default group = dxml.get_widget("iscsiRadio").get_group() for button in group: @@ -379,6 +459,8 @@ class PartitionTypeWindow(InstallWindow): return if dxml.get_widget("iscsiRadio").get_active() and iscsi.has_iscsi(): rc = self.addIscsiDrive() + elif dxml.get_widget("fcoeRadio").get_active() and fcoe.has_fcoe(): + rc = self.addFcoeDrive() elif dxml.get_widget("zfcpRadio") is not None and dxml.get_widget("zfcpRadio").get_active(): rc = self.addZfcpDrive() dialog.destroy() @@ -498,7 +580,7 @@ class PartitionTypeWindow(InstallWindow): self.xml.get_widget("bootDriveCombo").set_sensitive(False) self.xml.get_widget("encryptButton").set_sensitive(False) - if not iutil.isS390() and not iscsi.has_iscsi(): + if not iutil.isS390() and not iscsi.has_iscsi() and not fcoe.has_fcoe(): self.xml.get_widget("addButton").set_sensitive(False) sigs = { "on_partitionTypeCombo_changed": self.comboChanged, diff --git a/storage/__init__.py b/storage/__init__.py index 623eff1..6fdb086 100644 --- a/storage/__init__.py +++ b/storage/__init__.py @@ -46,6 +46,7 @@ from devicelibs.lvm import safeLvmName from devicelibs.dm import name_from_dm_node from udev import * import iscsi +import fcoe import zfcp import gettext @@ -204,6 +205,7 @@ class Storage(object): self.__luksDevs = {} self.iscsi = iscsi.iscsi() + self.fcoe = fcoe.fcoe() self.zfcp = zfcp.ZFCP() self._nextID = 0 @@ -269,6 +271,7 @@ class Storage(object): w = self.anaconda.intf.waitWindow(_("Finding Devices"), _("Finding storage devices...")) self.iscsi.startup(self.anaconda.intf) + self.fcoe.startup(self.anaconda.intf) self.zfcp.startup() if self.anaconda.id.getUpgrade(): clearPartType = CLEARPART_TYPE_NONE @@ -911,6 +914,7 @@ class Storage(object): def write(self, instPath): self.fsset.write(instPath) self.iscsi.write(instPath, self.anaconda) + self.fcoe.write(instPath, self.anaconda) self.zfcp.write(instPath) def writeKS(self, f): @@ -978,6 +982,7 @@ class Storage(object): f.write("\n") self.iscsi.writeKS(f) + self.fcoe.writeKS(f) self.zfcp.writeKS(f) diff --git a/storage/fcoe.py b/storage/fcoe.py new file mode 100644 index 0000000..46c5bcb --- /dev/null +++ b/storage/fcoe.py @@ -0,0 +1,92 @@ +# +# fcoe.py - fcoe class +# +# Copyright (C) 2009 Red Hat, Inc. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty 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, see <http://www.gnu.org/licenses/>. +# + +import os +import iutil +import logging +import time +log = logging.getLogger("anaconda") + +import gettext +_ = lambda x: gettext.ldgettext("anaconda", x) + +_fcoe_module_loaded = False + +def has_fcoe(): + global _fcoe_module_loaded + if not _fcoe_module_loaded: + iutil.execWithRedirect("modprobe", [ "fcoe" ], + stdout = "/dev/tty5", stderr="/dev/tty5", + searchPath = 1) + _fcoe_module_loaded = True + + return os.access("/sys/module/fcoe", os.X_OK) + +class fcoe(object): + def __init__(self): + self.started = False + self.nics = [] + + def _stabilize(self, intf = None): + if intf: + w = intf.waitWindow(_("Connecting to FCoE SAN"), + _("Connecting to FCoE SAN")) + + # I have no clue how long we need to wait, this ought to do the trick + time.sleep(10) + iutil.execWithRedirect("udevadm", [ "settle" ], + stdout = "/dev/tty5", stderr="/dev/tty5", + searchPath = 1) + if intf: + w.pop() + + def startup(self, intf = None): + if self.started: + return + + if not has_fcoe(): + return + + # Place holder for adding autodetection of FCoE setups based on + # firmware tables (like iBFT for iSCSI) + + self.started = True + + def addSan(self, nic, intf=None): + if not has_fcoe(): + raise IOError, _("FCoE not available") + + log.info("Activating FCoE SAN attached to %s" % nic) + + f = open("/sys/module/fcoe/parameters/create", "w") + f.write(nic) + f.close() + + self._stabilize(intf) + self.nics.append(nic) + + def writeKS(self, f): + # fixme plenty (including add ks support for fcoe in general) + return + + def write(self, instPath, anaconda): + # erm, do we need todo anything here ? + return + +# vim:tw=78:ts=4:et:sw=4 diff --git a/textw/partition_text.py b/textw/partition_text.py index fdf3496..f14a273 100644 --- a/textw/partition_text.py +++ b/textw/partition_text.py @@ -162,6 +162,9 @@ class PartitionTypeWindow: newdrv.append("Add iSCSI target") if iutil.isS390(): newdrv.append( "Add zFCP LUN" ) + from storage import fcoe + if fcoe.has_fcoe(): + newdrv.append("Add FCoE SAN") if len(newdrv) == 0: return INSTALL_BACK @@ -176,12 +179,18 @@ class PartitionTypeWindow: if button == TEXT_BACK_CHECK: return INSTALL_BACK - if choice == 1: + if newdrv[choice] == "Add zFCP LUN": try: return self.addZFCPDriveDialog(screen) except ValueError, e: ButtonChoiceWindow(screen, _("Error"), str(e)) return INSTALL_BACK + elif newdrv[choice] == "Add FCoE SAN": + try: + return self.addFcoeDriveDialog(screen) + except ValueError, e: + ButtonChoiceWindow(screen, _("Error"), str(e)) + return INSTALL_BACK else: try: return self.addIscsiDriveDialog(screen) @@ -206,6 +215,24 @@ class PartitionTypeWindow: return INSTALL_OK + def addFcoeDriveDialog(self, screen): + (button, entries) = EntryWindow(screen, + _("Add FCoE SAN"), + _("Enter the device name for the NIC which is connected to the FCoE SAN. For example \"eth0\"."), + prompts = [ _("NIC device name") ] ) + if button == TEXT_CANCEL_CHECK: + return INSTALL_BACK + + nic = entries[0].strip() + if nic not in self.anaconda.id.network.available(): + ButtonChoiceWindow(screen, _("Error"), + _("%s is not a valid NIC device name.") % nic) + return INSTALL_BACK + + self.anaconda.id.storage.fcoe.addSan(nic) + + return INSTALL_OK + def addIscsiDriveDialog(self, screen): if not network.hasActiveNetDev(): ButtonChoiceWindow(screen, _("Error"), diff --git a/ui/adddrive.glade b/ui/adddrive.glade index 599ed79..2d991ef 100644 --- a/ui/adddrive.glade +++ b/ui/adddrive.glade @@ -202,6 +202,25 @@ </child> <child> + <widget class="GtkRadioButton" id="fcoeRadio"> + <property name="visible">True</property> + <property name="label" translatable="yes" context="yes">Add _FCoE SAN</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> + <property name="group">iscsiRadio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> <widget class="GtkRadioButton" id="radiobutton1"> <property name="visible">True</property> <property name="sensitive">False</property> diff --git a/ui/fcoe-config.glade b/ui/fcoe-config.glade new file mode 100644 index 0000000..7034064 --- /dev/null +++ b/ui/fcoe-config.glade @@ -0,0 +1,149 @@ +<?xml version="1.0"?> +<glade-interface> + <!-- interface-requires gtk+ 2.16 --> + <!-- interface-naming-policy toplevel-contextual --> + <widget class="GtkDialog" id="fcoeDialog"> + <property name="title" translatable="yes">Configure FCoE Parameters</property> + <property name="window_position">center</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="border_width">12</property> + <property name="spacing">12</property> + <child> + <widget class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="label" translatable="yes">Please select the network interface which is connected to +your FCoE switch.</property> + <property name="wrap">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <widget class="GtkTable" id="fcoeTable"> + <property name="visible">True</property> + <property name="border_width">12</property> + <property name="n_columns">2</property> + <property name="column_spacing">6</property> + <property name="row_spacing">6</property> + <child> + <widget class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="label" translatable="yes">NIC</property> + </widget> + </child> + <child> + <widget class="GtkComboBox" id="fcoeNicCombo"> + <property name="visible">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + </widget> + <packing> + <property name="position">2</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="position">2</property> + </packing> + </child> + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <widget class="GtkButton" id="button1"> + <property name="label">gtk-cancel</property> + <property name="response_id">-6</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkButton" id="button2"> + <property name="response_id">-10</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <child> + <widget class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="spacing">2</property> + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="stock">gtk-add</property> + <property name="icon-size">4</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Add FCoE Disk(s)</property> + <property name="use_underline">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </widget> + </child> + </widget> +</glade-interface> -- 1.6.2.2 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list