summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--iw/autopart_type.py84
-rw-r--r--storage/__init__.py5
-rw-r--r--storage/fcoe.py92
-rw-r--r--textw/partition_text.py29
-rw-r--r--ui/adddrive.glade19
-rw-r--r--ui/fcoe-config.glade149
6 files changed, 376 insertions, 2 deletions
diff --git a/iw/autopart_type.py b/iw/autopart_type.py
index 8a1268904..9c04e52b2 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 572c7448e..03b987619 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
@@ -913,6 +916,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):
@@ -980,6 +984,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 000000000..46c5bcb9c
--- /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 fdf349666..f14a273d6 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 599ed79d7..2d991ef54 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 000000000..703406464
--- /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>