[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[PATCH] Initial FCoE support



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 4d9953c..77b2980 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()
@@ -490,7 +572,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 7000b26..45eabe0 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
@@ -215,6 +216,7 @@ class Storage(object):
         self.__luksDevs = {}
 
         self.iscsi = iscsi.iscsi()
+        self.fcoe = fcoe.fcoe()
         self.zfcp = zfcp.ZFCP()
 
         self._nextID = 0
@@ -280,6 +282,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() or not self.anaconda.isKickstart:
             # clearPartType defaults to CLEARPART_TYPE_LINUX, but the user
@@ -946,6 +949,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):
@@ -1013,6 +1017,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 48b7c18..452e9c7 100644
--- a/textw/partition_text.py
+++ b/textw/partition_text.py
@@ -157,6 +157,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
@@ -171,12 +174,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)
@@ -201,6 +210,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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]