iSCSI interface binding support (bz #500273)
Notes:
* Requires changes in dracut: https://bugzilla.redhat.com/show_bug.cgi?id=797158 and further in iscsi-initiator-utils, fresh build: https://brewweb.devel.redhat.com/taskinfo?taskID=4085771 New parameters passed to dracut are described in commit message.
* support for GUI, TUI, and kickstart (iscsi --iface option)
* All devices must be either bound or using default. More fine-grained implementation would require deeper and invasive changes in GUI and libiscsi. Moreover, combining binding and default doesn't seem as useful or legitmate use case.
* Discovery is done for all active interfaces. If user wants to activate additional interface in GUI (activating all needed interfaces in kickstart using network --activate is expected/recommended) and access a target via added interface it must be done before first login to a node of given target. We don't allow re-discovery of targets with nodes logged in as it can corrupt their authentication info. To offer activating of additional devices in GUI "Configure Network" button is added to Add Advanced Target dialog. It just runs nm-c-e as in hostname screen so user has to check Connect Automatically to activate the device (document).
* No iBFT support yet. We need to figure out what to pass to dracut and whether dracut can handle it. I have quite simple patch to support iBFT in anaconda ready. 6.4 stuff?
* I may squash some of the patches before pushing, I am leaving them split for review.
Updates image for RHEL6.3-20120226.n.0 nightly (and hopefuly some later): http://rvykydal.fedorapeople.org/updates.iscsibind.img
Screencast of GUI session: http://rvykydal.fedorapeople.org/iscsibind.ogg Screencast of TUI session: http://rvykydal.fedorapeople.org/iscsibind_tui.ogg
Resolves: rhbz#500273
In this initial support all used nodes will be either iface bound using default iface. --- iw/advanced_storage.py | 18 ++++++++++++++++-- storage/iscsi.py | 43 +++++++++++++++++++++++++++++++++++++++++++ ui/adddrive.glade | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-)
diff --git a/iw/advanced_storage.py b/iw/advanced_storage.py index 6384d5f..a21a8e7 100644 --- a/iw/advanced_storage.py +++ b/iw/advanced_storage.py @@ -394,7 +394,7 @@ def addFcoeDrive(anaconda): dialog.destroy() return rc
-def addIscsiDrive(anaconda): +def addIscsiDrive(anaconda, bind=False): """ Displays a series of dialogs that walk the user through discovering and logging into iscsi nodes. @@ -409,6 +409,15 @@ def addIscsiDrive(anaconda): return gtk.RESPONSE_CANCEL urlgrabber.grabber.reset_curl_obj()
+ # This will modify behaviour of iscsi.discovery() function + if storage.iscsi.iscsi().mode == "none" and not bind: + storage.iscsi.iscsi().delete_interfaces() + elif (storage.iscsi.iscsi().mode == "none" and bind + or storage.iscsi.iscsi().mode == "bind"): + active = set(network.getActiveNetDevs()) + created = set(storage.iscsi.iscsi().ifaces.values()) + storage.iscsi.iscsi().create_interfaces(active - created) + wizard = iSCSIGuiWizard() login_ok_nodes = pih.drive_iscsi_addition(anaconda, wizard) if len(login_ok_nodes): @@ -456,6 +465,10 @@ def addDrive(anaconda): if not storage.iscsi.has_iscsi(): dxml.get_widget("iscsiRadio").set_sensitive(False) dxml.get_widget("iscsiRadio").set_active(False) + dxml.get_widget("iscsiBindCheck").set_sensitive(False) + else: + dxml.get_widget("iscsiBindCheck").set_active(bool(storage.iscsi.iscsi().ifaces)) + dxml.get_widget("iscsiBindCheck").set_sensitive(storage.iscsi.iscsi().mode == "none")
if not storage.fcoe.has_fcoe(): dxml.get_widget("fcoeRadio").set_sensitive(False) @@ -476,7 +489,8 @@ def addDrive(anaconda): return False
if dxml.get_widget("iscsiRadio").get_active() and storage.iscsi.has_iscsi(): - rc = addIscsiDrive(anaconda) + bind = dxml.get_widget("iscsiBindCheck").get_active() + rc = addIscsiDrive(anaconda, bind) elif dxml.get_widget("fcoeRadio").get_active() and storage.fcoe.has_fcoe(): rc = addFcoeDrive(anaconda) elif dxml.get_widget("zfcpRadio") is not None and dxml.get_widget("zfcpRadio").get_active(): diff --git a/storage/iscsi.py b/storage/iscsi.py index d44b822..f4dfee4 100644 --- a/storage/iscsi.py +++ b/storage/iscsi.py @@ -103,6 +103,7 @@ class iscsi(object): self._initiator = "" self.initiatorSet = False self.started = False + self.ifaces = {}
if flags.ibft: try: @@ -142,6 +143,17 @@ class iscsi(object): itertools.chain(*self.discovered_targets.values()) if logged_in] + self.ibftNodes
+ def _getMode(self): + if not self.active_nodes(): + return "none" + else: + if self.ifaces: + return "bind" + else: + return "default" + + mode = property(_getMode) + def _mark_node_active(self, node, active=True): """Mark node as one logged in to
@@ -189,6 +201,37 @@ class iscsi(object): if intf: w.pop()
+ def create_interfaces(self, ifaces): + for iface in ifaces: + iscsi_iface_name = "iface%d" % len(self.ifaces) + #iscsiadm -m iface -I iface0 --op=new + iutil.execWithRedirect("iscsiadm", + ["-m", "iface", "-I", iscsi_iface_name, "--op=new"], + stdout="/dev/tty5", + stderr="/dev/tty5") + #iscsiadm -m iface -I iface0 --op=update -n iface.net_ifacename -v eth0 + iutil.execWithRedirect("iscsiadm", + ["-m", "iface", "-I", iscsi_iface_name, + "--op=update", "-n", + "iface.net_ifacename", "-v", iface], + stdout="/dev/tty5", + stderr="/dev/tty5") + + self.ifaces[iscsi_iface_name] = iface + log.debug("created_interface %s:%s" % (iscsi_iface_name, iface)) + + def delete_interfaces(self): + if not self.ifaces: + return None + for iscsi_iface_name in self.ifaces: + #iscsiadm -m iface -I iface0 --op=delete + iutil.execWithRedirect("iscsiadm", + ["-m", "iface", "-I", iscsi_iface_name, + "--op=delete"], + stdout="/dev/tty5", + stderr="/dev/tty5") + self.ifaces = {} + def startup(self, intf = None): if self.started: return diff --git a/ui/adddrive.glade b/ui/adddrive.glade index a085176..5440966 100644 --- a/ui/adddrive.glade +++ b/ui/adddrive.glade @@ -184,6 +184,39 @@ </child>
<child> + <widget class="GtkAlignment" id="alignment2"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">18</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkCheckButton" id="iscsiBindCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Bind targets to network interfaces</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> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> <widget class="GtkRadioButton" id="zfcpRadio"> <property name="visible">True</property> <property name="label" translatable="yes">Add _ZFCP LUN</property>
Ack, with comments below.
On Tue, Feb 28, 2012 at 12:03:28PM +0100, Radek Vykydal wrote:
Resolves: rhbz#500273
In this initial support all used nodes will be either iface bound using default iface.
iw/advanced_storage.py | 18 ++++++++++++++++-- storage/iscsi.py | 43 +++++++++++++++++++++++++++++++++++++++++++ ui/adddrive.glade | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-)
diff --git a/iw/advanced_storage.py b/iw/advanced_storage.py index 6384d5f..a21a8e7 100644 --- a/iw/advanced_storage.py +++ b/iw/advanced_storage.py @@ -394,7 +394,7 @@ def addFcoeDrive(anaconda): dialog.destroy() return rc
-def addIscsiDrive(anaconda): +def addIscsiDrive(anaconda, bind=False): """ Displays a series of dialogs that walk the user through discovering and logging into iscsi nodes. @@ -409,6 +409,15 @@ def addIscsiDrive(anaconda): return gtk.RESPONSE_CANCEL urlgrabber.grabber.reset_curl_obj()
- # This will modify behaviour of iscsi.discovery() function
- if storage.iscsi.iscsi().mode == "none" and not bind:
storage.iscsi.iscsi().delete_interfaces()
- elif (storage.iscsi.iscsi().mode == "none" and bind
or storage.iscsi.iscsi().mode == "bind"):
I'm not liking how this reads. I can read it as:
elif (storage.iscsi.iscsi().mode == "none" and bind) or \ storage.iscsi.iscsi().mode == "bind"
or:
elif storage.iscsi.iscsi().mode == "none" and \ (storage.iscsi.iscsi().mode == "bind" or bind)
I say it needs better parens for readability.
active = set(network.getActiveNetDevs())
created = set(storage.iscsi.iscsi().ifaces.values())
storage.iscsi.iscsi().create_interfaces(active - created)
- wizard = iSCSIGuiWizard() login_ok_nodes = pih.drive_iscsi_addition(anaconda, wizard) if len(login_ok_nodes):
@@ -456,6 +465,10 @@ def addDrive(anaconda): if not storage.iscsi.has_iscsi(): dxml.get_widget("iscsiRadio").set_sensitive(False) dxml.get_widget("iscsiRadio").set_active(False)
dxml.get_widget("iscsiBindCheck").set_sensitive(False)
else:
dxml.get_widget("iscsiBindCheck").set_active(bool(storage.iscsi.iscsi().ifaces))
dxml.get_widget("iscsiBindCheck").set_sensitive(storage.iscsi.iscsi().mode == "none")
if not storage.fcoe.has_fcoe(): dxml.get_widget("fcoeRadio").set_sensitive(False)
@@ -476,7 +489,8 @@ def addDrive(anaconda): return False
if dxml.get_widget("iscsiRadio").get_active() and storage.iscsi.has_iscsi():
rc = addIscsiDrive(anaconda)
bind = dxml.get_widget("iscsiBindCheck").get_active()
elif dxml.get_widget("fcoeRadio").get_active() and storage.fcoe.has_fcoe(): rc = addFcoeDrive(anaconda) elif dxml.get_widget("zfcpRadio") is not None and dxml.get_widget("zfcpRadio").get_active():rc = addIscsiDrive(anaconda, bind)
diff --git a/storage/iscsi.py b/storage/iscsi.py index d44b822..f4dfee4 100644 --- a/storage/iscsi.py +++ b/storage/iscsi.py @@ -103,6 +103,7 @@ class iscsi(object): self._initiator = "" self.initiatorSet = False self.started = False
self.ifaces = {} if flags.ibft: try:
@@ -142,6 +143,17 @@ class iscsi(object): itertools.chain(*self.discovered_targets.values()) if logged_in] + self.ibftNodes
- def _getMode(self):
if not self.active_nodes():
return "none"
else:
if self.ifaces:
return "bind"
else:
return "default"
This if/else block doesn't really need to be in an else block by itself.
- mode = property(_getMode)
- def _mark_node_active(self, node, active=True): """Mark node as one logged in to
@@ -189,6 +201,37 @@ class iscsi(object): if intf: w.pop()
- def create_interfaces(self, ifaces):
for iface in ifaces:
iscsi_iface_name = "iface%d" % len(self.ifaces)
#iscsiadm -m iface -I iface0 --op=new
iutil.execWithRedirect("iscsiadm",
["-m", "iface", "-I", iscsi_iface_name, "--op=new"],
stdout="/dev/tty5",
stderr="/dev/tty5")
#iscsiadm -m iface -I iface0 --op=update -n iface.net_ifacename -v eth0
iutil.execWithRedirect("iscsiadm",
["-m", "iface", "-I", iscsi_iface_name,
"--op=update", "-n",
"iface.net_ifacename", "-v", iface],
stdout="/dev/tty5",
stderr="/dev/tty5")
self.ifaces[iscsi_iface_name] = iface
log.debug("created_interface %s:%s" % (iscsi_iface_name, iface))
- def delete_interfaces(self):
if not self.ifaces:
return None
for iscsi_iface_name in self.ifaces:
#iscsiadm -m iface -I iface0 --op=delete
iutil.execWithRedirect("iscsiadm",
["-m", "iface", "-I", iscsi_iface_name,
"--op=delete"],
stdout="/dev/tty5",
stderr="/dev/tty5")
self.ifaces = {}
- def startup(self, intf = None): if self.started: return
diff --git a/ui/adddrive.glade b/ui/adddrive.glade index a085176..5440966 100644 --- a/ui/adddrive.glade +++ b/ui/adddrive.glade @@ -184,6 +184,39 @@ </child>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">18</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkCheckButton" id="iscsiBindCheck">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">_Bind targets to network interfaces</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>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="zfcpRadio"> <property name="visible">True</property> <property name="label" translatable="yes">Add _ZFCP LUN</property>
-- 1.7.4
Anaconda-devel-list mailing list Anaconda-devel-list@redhat.com https://www.redhat.com/mailman/listinfo/anaconda-devel-list
On 02/28/2012 07:31 PM, David Cantrell wrote:
Ack, with comments below.
On Tue, Feb 28, 2012 at 12:03:28PM +0100, Radek Vykydal wrote:
- # This will modify behaviour of iscsi.discovery() function
- if storage.iscsi.iscsi().mode == "none" and not bind:
storage.iscsi.iscsi().delete_interfaces()
- elif (storage.iscsi.iscsi().mode == "none" and bind
or storage.iscsi.iscsi().mode == "bind"):
I'm not liking how this reads. I can read it as:
elif (storage.iscsi.iscsi().mode == "none" and bind) or \ storage.iscsi.iscsi().mode == "bind"
or:
elif storage.iscsi.iscsi().mode == "none" and \ (storage.iscsi.iscsi().mode == "bind" or bind)
I say it needs better parens for readability.
I'll add parens.
- def _getMode(self):
if not self.active_nodes():
return "none"
else:
if self.ifaces:
return "bind"
else:
return "default"
This if/else block doesn't really need to be in an else block by itself.
Sure, I'll fix it.
Resolves: rhbz#500273
Also write out proper dracut options:
netroot=iscsi:[<servername>]:[<protocol>]:[<port>]: [<iscsi_iface_name>]:[<netdev_name>]:[<LUN>]:<targetname> --- network.py | 22 ++++++++-------------- storage/devices.py | 16 +++++++++++++--- storage/devicetree.py | 9 ++++++--- storage/iscsi.py | 4 ++-- storage/udev.py | 6 ++++++ 5 files changed, 35 insertions(+), 22 deletions(-)
diff --git a/network.py b/network.py index 98dd4af..ec35068 100644 --- a/network.py +++ b/network.py @@ -279,7 +279,7 @@ class NetworkDevice(IfcfgFile): def usedByFCoE(self, anaconda): import storage for d in anaconda.id.storage.devices: - if (isinstance(d, storage.devices.NetworkStorageDevice) and + if (isinstance(d, storage.devices.FcoeDiskDevice) and d.nic == self.iface): return True return False @@ -288,20 +288,14 @@ class NetworkDevice(IfcfgFile): import storage rootdev = anaconda.id.storage.rootDevice for d in anaconda.id.storage.devices: - if (isinstance(d, storage.devices.NetworkStorageDevice) and - d.host_address and + if (isinstance(d, storage.devices.iScsiDiskDevice) and rootdev.dependsOn(d)): - if self.iface == ifaceForHostIP(d.host_address): - return True - return False - - def usedByISCSI(self, anaconda): - import storage - for d in anaconda.id.storage.devices: - if (isinstance(d, storage.devices.NetworkStorageDevice) and - d.host_address): - if self.iface == ifaceForHostIP(d.host_address): - return True + if d.nic: + if self.iface == d.nic: + return True + else: + if self.iface == ifaceForHostIP(d.host_address): + return True return False
class Network: diff --git a/storage/devices.py b/storage/devices.py index 3810b24..d847cb9 100644 --- a/storage/devices.py +++ b/storage/devices.py @@ -3609,10 +3609,16 @@ class iScsiDiskDevice(DiskDevice, NetworkStorageDevice): def __init__(self, device, **kwargs): self.node = kwargs.pop("node") self.ibft = kwargs.pop("ibft") + self.nic = kwargs.pop("nic") self.initiator = kwargs.pop("initiator") DiskDevice.__init__(self, device, **kwargs) - NetworkStorageDevice.__init__(self, host_address=self.node.address) - log.debug("created new iscsi disk %s %s:%d" % (self.node.name, self.node.address, self.node.port)) + NetworkStorageDevice.__init__(self, host_address=self.node.address, + nic=self.nic) + log.debug("created new iscsi disk %s %s:%d via %s:%s" % (self.node.name, + self.node.address, + self.node.port, + self.node.iface, + self.nic))
def dracutSetupArgs(self): if self.ibft: @@ -3631,7 +3637,11 @@ class iScsiDiskDevice(DiskDevice, NetworkStorageDevice): netroot += ":%s:%s" % (auth.reverse_username, auth.reverse_password)
- netroot += "@%s::%d::%s" % (address, self.node.port, self.node.name) + netroot += "@%s::%d:%s:%s::%s" % (address, + self.node.port, + self.node.iface, + self.nic, + self.node.name)
initiator = "iscsi_initiator=%s" % self.initiator
diff --git a/storage/devicetree.py b/storage/devicetree.py index ffd6732..e6ae639 100644 --- a/storage/devicetree.py +++ b/storage/devicetree.py @@ -1180,11 +1180,14 @@ class DeviceTree(object): kwargs = { "serial": serial, "vendor": vendor, "bus": bus } if udev_device_is_iscsi(info): diskType = iScsiDiskDevice - kwargs["node"] = self.iscsi.getNode( + node = self.iscsi.getNode( udev_device_get_iscsi_name(info), udev_device_get_iscsi_address(info), - udev_device_get_iscsi_port(info)) - kwargs["ibft"] = kwargs["node"] in self.iscsi.ibftNodes + udev_device_get_iscsi_port(info), + udev_device_get_iscsi_nic(info)) + kwargs["node"] = node + kwargs["nic"] = self.iscsi.ifaces.get(node.iface, node.iface) + kwargs["ibft"] = node in self.iscsi.ibftNodes kwargs["initiator"] = self.iscsi.initiator log.debug("%s is an iscsi disk" % name) elif udev_device_is_fcoe(info): diff --git a/storage/iscsi.py b/storage/iscsi.py index f4dfee4..34c4ad0 100644 --- a/storage/iscsi.py +++ b/storage/iscsi.py @@ -446,10 +446,10 @@ class iscsi(object): shutil.copytree("/var/lib/iscsi", instPath + "/var/lib/iscsi", symlinks=True)
- def getNode(self, name, address, port): + def getNode(self, name, address, port, iface): for node in self.active_nodes(): if node.name == name and node.address == address and \ - node.port == int(port): + node.port == int(port) and node.iface == iface: return node
return None diff --git a/storage/udev.py b/storage/udev.py index d9a5d13..7890c17 100644 --- a/storage/udev.py +++ b/storage/udev.py @@ -553,6 +553,12 @@ def udev_device_get_iscsi_port(info): # IPV6 contains : within the address, the part after the last : is the port return path_components[address_field].split(":")[-1]
+def udev_device_get_iscsi_nic(info): + session = info["sysfs_path"].split("/")[4] + iface = open("/sys/class/iscsi_session/%s/ifacename" % + session).read().strip() + return iface + # fcoe disks have ID_PATH in the form of: # For FCoE directly over the NIC (so no VLAN and thus no DCB): # pci-eth#-fc-${id}
Ack, with comments.
On Tue, Feb 28, 2012 at 12:03:29PM +0100, Radek Vykydal wrote:
Resolves: rhbz#500273
Also write out proper dracut options:
netroot=iscsi:[<servername>]:[<protocol>]:[<port>]: [<iscsi_iface_name>]:[<netdev_name>]:[<LUN>]:<targetname>
network.py | 22 ++++++++-------------- storage/devices.py | 16 +++++++++++++--- storage/devicetree.py | 9 ++++++--- storage/iscsi.py | 4 ++-- storage/udev.py | 6 ++++++ 5 files changed, 35 insertions(+), 22 deletions(-)
diff --git a/network.py b/network.py index 98dd4af..ec35068 100644 --- a/network.py +++ b/network.py @@ -279,7 +279,7 @@ class NetworkDevice(IfcfgFile): def usedByFCoE(self, anaconda): import storage for d in anaconda.id.storage.devices:
if (isinstance(d, storage.devices.NetworkStorageDevice) and
if (isinstance(d, storage.devices.FcoeDiskDevice) and d.nic == self.iface): return True return False
@@ -288,20 +288,14 @@ class NetworkDevice(IfcfgFile): import storage rootdev = anaconda.id.storage.rootDevice for d in anaconda.id.storage.devices:
if (isinstance(d, storage.devices.NetworkStorageDevice) and
d.host_address and
if (isinstance(d, storage.devices.iScsiDiskDevice) and rootdev.dependsOn(d)):
if self.iface == ifaceForHostIP(d.host_address):
return True
return False
- def usedByISCSI(self, anaconda):
import storage
for d in anaconda.id.storage.devices:
if (isinstance(d, storage.devices.NetworkStorageDevice) and
d.host_address):
if self.iface == ifaceForHostIP(d.host_address):
return True
if d.nic:
if self.iface == d.nic:
return True
This could be reduced to:
if d.nic and self.iface == d.nic: return True
else:
if self.iface == ifaceForHostIP(d.host_address):
return True
These could just be merged to an elif line.
return False
class Network: diff --git a/storage/devices.py b/storage/devices.py index 3810b24..d847cb9 100644 --- a/storage/devices.py +++ b/storage/devices.py @@ -3609,10 +3609,16 @@ class iScsiDiskDevice(DiskDevice, NetworkStorageDevice): def __init__(self, device, **kwargs): self.node = kwargs.pop("node") self.ibft = kwargs.pop("ibft")
self.nic = kwargs.pop("nic") self.initiator = kwargs.pop("initiator") DiskDevice.__init__(self, device, **kwargs)
NetworkStorageDevice.__init__(self, host_address=self.node.address)
log.debug("created new iscsi disk %s %s:%d" % (self.node.name, self.node.address, self.node.port))
NetworkStorageDevice.__init__(self, host_address=self.node.address,
nic=self.nic)
log.debug("created new iscsi disk %s %s:%d via %s:%s" % (self.node.name,
self.node.address,
self.node.port,
self.node.iface,
self.nic))
def dracutSetupArgs(self): if self.ibft:
@@ -3631,7 +3637,11 @@ class iScsiDiskDevice(DiskDevice, NetworkStorageDevice): netroot += ":%s:%s" % (auth.reverse_username, auth.reverse_password)
netroot += "@%s::%d::%s" % (address, self.node.port, self.node.name)
netroot += "@%s::%d:%s:%s::%s" % (address,
self.node.port,
self.node.iface,
self.nic,
self.node.name) initiator = "iscsi_initiator=%s" % self.initiator
diff --git a/storage/devicetree.py b/storage/devicetree.py index ffd6732..e6ae639 100644 --- a/storage/devicetree.py +++ b/storage/devicetree.py @@ -1180,11 +1180,14 @@ class DeviceTree(object): kwargs = { "serial": serial, "vendor": vendor, "bus": bus } if udev_device_is_iscsi(info): diskType = iScsiDiskDevice
kwargs["node"] = self.iscsi.getNode(
node = self.iscsi.getNode( udev_device_get_iscsi_name(info), udev_device_get_iscsi_address(info),
udev_device_get_iscsi_port(info))
kwargs["ibft"] = kwargs["node"] in self.iscsi.ibftNodes
udev_device_get_iscsi_port(info),
udev_device_get_iscsi_nic(info))
kwargs["node"] = node
kwargs["nic"] = self.iscsi.ifaces.get(node.iface, node.iface)
kwargs["ibft"] = node in self.iscsi.ibftNodes kwargs["initiator"] = self.iscsi.initiator log.debug("%s is an iscsi disk" % name) elif udev_device_is_fcoe(info):
diff --git a/storage/iscsi.py b/storage/iscsi.py index f4dfee4..34c4ad0 100644 --- a/storage/iscsi.py +++ b/storage/iscsi.py @@ -446,10 +446,10 @@ class iscsi(object): shutil.copytree("/var/lib/iscsi", instPath + "/var/lib/iscsi", symlinks=True)
- def getNode(self, name, address, port):
- def getNode(self, name, address, port, iface): for node in self.active_nodes(): if node.name == name and node.address == address and \
node.port == int(port):
node.port == int(port) and node.iface == iface: return node return None
diff --git a/storage/udev.py b/storage/udev.py index d9a5d13..7890c17 100644 --- a/storage/udev.py +++ b/storage/udev.py @@ -553,6 +553,12 @@ def udev_device_get_iscsi_port(info): # IPV6 contains : within the address, the part after the last : is the port return path_components[address_field].split(":")[-1]
+def udev_device_get_iscsi_nic(info):
- session = info["sysfs_path"].split("/")[4]
- iface = open("/sys/class/iscsi_session/%s/ifacename" %
session).read().strip()
- return iface
# fcoe disks have ID_PATH in the form of: # For FCoE directly over the NIC (so no VLAN and thus no DCB):
# pci-eth#-fc-${id}
1.7.4
Anaconda-devel-list mailing list Anaconda-devel-list@redhat.com https://www.redhat.com/mailman/listinfo/anaconda-devel-list
On 02/28/2012 07:39 PM, David Cantrell wrote:
Ack, with comments.
On Tue, Feb 28, 2012 at 12:03:29PM +0100, Radek Vykydal wrote:
- def usedByISCSI(self, anaconda):
import storage
for d in anaconda.id.storage.devices:
if (isinstance(d, storage.devices.NetworkStorageDevice) and
d.host_address):
if self.iface == ifaceForHostIP(d.host_address):
return True
if d.nic:
if self.iface == d.nic:
return True
This could be reduced to:
if d.nic and self.iface == d.nic: return True
You may have overlooked that the block is in a loop, so the behaviour for:
bool(d.nic) = True self.iface != d.nic self.iface == ifaceForHostIP(d.host_address)
from doing next cycle to returning True
else:
if self.iface == ifaceForHostIP(d.host_address):
return True
These could just be merged to an elif line.
sure, I found it expressing what it should represent more clearly this way, perhaps this would be more clear:
# device bound to interface if d.nic: if self.iface == d.nic: return True # device using default interface else: if self.iface == ifaceForHostIP(d.host_address): return True
On 02/28/2012 08:46 PM, Radek Vykydal wrote:
You may have overlooked that the block is in a loop, so the behaviour for:
bool(d.nic) = True self.iface != d.nic self.iface == ifaceForHostIP(d.host_address)
from doing next cycle to returning True
I mean: would change from doing next cycle to returning True
On Tue, Feb 28, 2012 at 08:46:23PM +0100, Radek Vykydal wrote:
On 02/28/2012 07:39 PM, David Cantrell wrote:
Ack, with comments.
On Tue, Feb 28, 2012 at 12:03:29PM +0100, Radek Vykydal wrote:
- def usedByISCSI(self, anaconda):
import storage
for d in anaconda.id.storage.devices:
if (isinstance(d, storage.devices.NetworkStorageDevice) and
d.host_address):
if self.iface == ifaceForHostIP(d.host_address):
return True
if d.nic:
if self.iface == d.nic:
return True
This could be reduced to:
if d.nic and self.iface == d.nic: return True
You may have overlooked that the block is in a loop, so the behaviour for:
bool(d.nic) = True self.iface != d.nic self.iface == ifaceForHostIP(d.host_address)
from doing next cycle to returning True
else:
if self.iface == ifaceForHostIP(d.host_address):
return True
These could just be merged to an elif line.
sure, I found it expressing what it should represent more clearly this way, perhaps this would be more clear:
# device bound to interface if d.nic: if self.iface == d.nic: return True # device using default interface else: if self.iface == ifaceForHostIP(d.host_address): return True
I did note that the block was in a loop, I was just seeing obvious test reductions. But I think I understand what you were going for now, so it's fine by me. Ack.
Resolves: rhbz#500273 --- iw/advanced_storage.py | 10 +++++++--- partIntfHelpers.py | 5 +++-- textw/add_drive_text.py | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/iw/advanced_storage.py b/iw/advanced_storage.py index a21a8e7..3918475 100644 --- a/iw/advanced_storage.py +++ b/iw/advanced_storage.py @@ -173,6 +173,7 @@ class iSCSILoginDialog(iSCSICredentialsDialog):
class iSCSIGuiWizard(pih.iSCSIWizard): NODE_NAME_COL = DeviceSelector.IMMUTABLE_COL + 1 + NODE_INTERFACE_COL = DeviceSelector.IMMUTABLE_COL + 2
def __init__(self): self.login_dialog = None @@ -223,7 +224,7 @@ class iSCSIGuiWizard(pih.iSCSIWizard):
return self._run_dialog(self.login_dialog.dialog)
- def display_nodes_dialog(self, found_nodes): + def display_nodes_dialog(self, found_nodes, ifaces): def _login_button_disabler(device_selector, login_button, checked, item): login_button.set_sensitive(len(device_selector.getSelected()) > 0)
@@ -233,14 +234,16 @@ class iSCSIGuiWizard(pih.iSCSIWizard): gobject.TYPE_BOOLEAN, # visible gobject.TYPE_BOOLEAN, # active (checked) gobject.TYPE_BOOLEAN, # immutable - gobject.TYPE_STRING # node name + gobject.TYPE_STRING, # node name + gobject.TYPE_STRING # node interface ) map(lambda node : store.append(None, ( node, # the object True, # visible True, # active False, # not immutable - node.name)), # node's name + node.name, # node's name + ifaces.get(node.iface, node.iface))), # node's interface found_nodes)
# create and setup the device selector @@ -255,6 +258,7 @@ class iSCSIGuiWizard(pih.iSCSIWizard): xml.get_widget("button_login")) ds.createSelectionCol(toggledCB=callback) ds.addColumn(_("Node Name"), self.NODE_NAME_COL) + ds.addColumn(_("Interface"), self.NODE_INTERFACE_COL) # attach the treeview to the dialog sw = xml.get_widget("nodes_scrolled_window") sw.add(view) diff --git a/partIntfHelpers.py b/partIntfHelpers.py index 7c318a5..c17945b 100644 --- a/partIntfHelpers.py +++ b/partIntfHelpers.py @@ -408,7 +408,7 @@ class iSCSIWizard(): pass
@abstractmethod - def display_nodes_dialog(self, found_nodes): + def display_nodes_dialog(self, found_nodes, ifaces): pass
@abstractmethod @@ -470,7 +470,8 @@ def drive_iscsi_addition(anaconda, wizard): anaconda.intf.messageWindow(_("iSCSI Nodes"), _("No iSCSI nodes to log in")) break - (rc, selected_nodes) = wizard.display_nodes_dialog(found_nodes) + (rc, selected_nodes) = wizard.display_nodes_dialog(found_nodes, + anaconda.id.storage.iscsi.ifaces) if not rc or len(selected_nodes) == 0: break step = STEP_LOGIN diff --git a/textw/add_drive_text.py b/textw/add_drive_text.py index 546e68d..8ba4da4 100644 --- a/textw/add_drive_text.py +++ b/textw/add_drive_text.py @@ -187,7 +187,7 @@ class iSCSITextWizard(pih.iSCSIWizard): # should never stop us: return True
- def display_nodes_dialog(self, found_nodes): + def display_nodes_dialog(self, found_nodes, iscsi_ifaces): grid_height = 4 basic_grid = None if self.listbox_login.current() not in \
Ack.
On Tue, Feb 28, 2012 at 12:03:30PM +0100, Radek Vykydal wrote:
Resolves: rhbz#500273
iw/advanced_storage.py | 10 +++++++--- partIntfHelpers.py | 5 +++-- textw/add_drive_text.py | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/iw/advanced_storage.py b/iw/advanced_storage.py index a21a8e7..3918475 100644 --- a/iw/advanced_storage.py +++ b/iw/advanced_storage.py @@ -173,6 +173,7 @@ class iSCSILoginDialog(iSCSICredentialsDialog):
class iSCSIGuiWizard(pih.iSCSIWizard): NODE_NAME_COL = DeviceSelector.IMMUTABLE_COL + 1
NODE_INTERFACE_COL = DeviceSelector.IMMUTABLE_COL + 2
def __init__(self): self.login_dialog = None
@@ -223,7 +224,7 @@ class iSCSIGuiWizard(pih.iSCSIWizard):
return self._run_dialog(self.login_dialog.dialog)
- def display_nodes_dialog(self, found_nodes):
- def display_nodes_dialog(self, found_nodes, ifaces): def _login_button_disabler(device_selector, login_button, checked, item): login_button.set_sensitive(len(device_selector.getSelected()) > 0)
@@ -233,14 +234,16 @@ class iSCSIGuiWizard(pih.iSCSIWizard): gobject.TYPE_BOOLEAN, # visible gobject.TYPE_BOOLEAN, # active (checked) gobject.TYPE_BOOLEAN, # immutable
gobject.TYPE_STRING # node name
gobject.TYPE_STRING, # node name
gobject.TYPE_STRING # node interface ) map(lambda node : store.append(None, ( node, # the object True, # visible True, # active False, # not immutable
node.name)), # node's name
node.name, # node's name
ifaces.get(node.iface, node.iface))), # node's interface found_nodes) # create and setup the device selector
@@ -255,6 +258,7 @@ class iSCSIGuiWizard(pih.iSCSIWizard): xml.get_widget("button_login")) ds.createSelectionCol(toggledCB=callback) ds.addColumn(_("Node Name"), self.NODE_NAME_COL)
ds.addColumn(_("Interface"), self.NODE_INTERFACE_COL) # attach the treeview to the dialog sw = xml.get_widget("nodes_scrolled_window") sw.add(view)
diff --git a/partIntfHelpers.py b/partIntfHelpers.py index 7c318a5..c17945b 100644 --- a/partIntfHelpers.py +++ b/partIntfHelpers.py @@ -408,7 +408,7 @@ class iSCSIWizard(): pass
@abstractmethod
- def display_nodes_dialog(self, found_nodes):
def display_nodes_dialog(self, found_nodes, ifaces): pass
@abstractmethod
@@ -470,7 +470,8 @@ def drive_iscsi_addition(anaconda, wizard): anaconda.intf.messageWindow(_("iSCSI Nodes"), _("No iSCSI nodes to log in")) break
(rc, selected_nodes) = wizard.display_nodes_dialog(found_nodes)
(rc, selected_nodes) = wizard.display_nodes_dialog(found_nodes,
anaconda.id.storage.iscsi.ifaces) if not rc or len(selected_nodes) == 0: break step = STEP_LOGIN
diff --git a/textw/add_drive_text.py b/textw/add_drive_text.py index 546e68d..8ba4da4 100644 --- a/textw/add_drive_text.py +++ b/textw/add_drive_text.py @@ -187,7 +187,7 @@ class iSCSITextWizard(pih.iSCSIWizard): # should never stop us: return True
- def display_nodes_dialog(self, found_nodes):
- def display_nodes_dialog(self, found_nodes, iscsi_ifaces): grid_height = 4 basic_grid = None if self.listbox_login.current() not in \
-- 1.7.4
Anaconda-devel-list mailing list Anaconda-devel-list@redhat.com https://www.redhat.com/mailman/listinfo/anaconda-devel-list
Resolves: rhbz#500273 --- iw/advanced_storage.py | 7 ++++--- partIntfHelpers.py | 6 ++++-- textw/add_drive_text.py | 3 ++- 3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/iw/advanced_storage.py b/iw/advanced_storage.py index 3918475..35e8a92 100644 --- a/iw/advanced_storage.py +++ b/iw/advanced_storage.py @@ -271,7 +271,8 @@ class iSCSIGuiWizard(pih.iSCSIWizard): dialog.destroy() return (rc, selected_nodes)
- def display_success_dialog(self, success_nodes, fail_nodes, fail_reason): + def display_success_dialog(self, success_nodes, fail_nodes, fail_reason, + ifaces): (xml, dialog) = gui.getGladeWidget("iscsi-dialogs.glade", "success_dialog") w_success = xml.get_widget("label_success") w_success_win = xml.get_widget("scroll_window_success") @@ -285,14 +286,14 @@ class iSCSIGuiWizard(pih.iSCSIWizard): w_separator = xml.get_widget("separator")
if success_nodes: - markup = "\n".join(map(lambda n: n.name, success_nodes)) + markup = "\n".join(map(lambda n: "%s via %s" % (n.name, ifaces.get(n.iface, n.iface)), success_nodes)) buf = gtk.TextBuffer() buf.set_text(markup) w_success.show() w_success_val.set_buffer(buf) w_success_win.show() if fail_nodes: - markup = "\n".join(map(lambda n: n.name, fail_nodes)) + markup = "\n".join(map(lambda n: "%s via %s" % (n.name, ifaces.get(n.iface, n.iface)), fail_nodes)) buf = gtk.TextBuffer() buf.set_text(markup) w_fail.show() diff --git a/partIntfHelpers.py b/partIntfHelpers.py index c17945b..9ce4afc 100644 --- a/partIntfHelpers.py +++ b/partIntfHelpers.py @@ -412,7 +412,8 @@ class iSCSIWizard(): pass
@abstractmethod - def display_success_dialog(self, success_nodes, fail_nodes, fail_reason): + def display_success_dialog(self, success_nodes, fail_nodes, fail_reason, + ifaces): pass
@abstractmethod @@ -497,7 +498,8 @@ def drive_iscsi_addition(anaconda, wizard): elif step == STEP_SUMMARY: rc = wizard.display_success_dialog(login_ok_nodes, login_fail_nodes, - login_fail_msg) + login_fail_msg, + anaconda.id.storage.iscsi.ifaces) if rc: step = STEP_STABILIZE else: diff --git a/textw/add_drive_text.py b/textw/add_drive_text.py index 8ba4da4..e196e2f 100644 --- a/textw/add_drive_text.py +++ b/textw/add_drive_text.py @@ -229,7 +229,8 @@ class iSCSITextWizard(pih.iSCSIWizard): if i in listbox.getSelection()] return (rc, selected_nodes)
- def display_success_dialog(self, success_nodes, fail_nodes, fail_reason): + def display_success_dialog(self, success_nodes, fail_nodes, fail_reason, + ifaces): buttons = [TEXT_OK_BUTTON] msg = _("Successfully logged into all the selected nodes.") msg_reason = _("Reason:")
Ack.
On Tue, Feb 28, 2012 at 12:03:31PM +0100, Radek Vykydal wrote:
Resolves: rhbz#500273
iw/advanced_storage.py | 7 ++++--- partIntfHelpers.py | 6 ++++-- textw/add_drive_text.py | 3 ++- 3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/iw/advanced_storage.py b/iw/advanced_storage.py index 3918475..35e8a92 100644 --- a/iw/advanced_storage.py +++ b/iw/advanced_storage.py @@ -271,7 +271,8 @@ class iSCSIGuiWizard(pih.iSCSIWizard): dialog.destroy() return (rc, selected_nodes)
- def display_success_dialog(self, success_nodes, fail_nodes, fail_reason):
- def display_success_dialog(self, success_nodes, fail_nodes, fail_reason,
ifaces): (xml, dialog) = gui.getGladeWidget("iscsi-dialogs.glade", "success_dialog") w_success = xml.get_widget("label_success") w_success_win = xml.get_widget("scroll_window_success")
@@ -285,14 +286,14 @@ class iSCSIGuiWizard(pih.iSCSIWizard): w_separator = xml.get_widget("separator")
if success_nodes:
markup = "\n".join(map(lambda n: n.name, success_nodes))
markup = "\n".join(map(lambda n: "%s via %s" % (n.name, ifaces.get(n.iface, n.iface)), success_nodes)) buf = gtk.TextBuffer() buf.set_text(markup) w_success.show() w_success_val.set_buffer(buf) w_success_win.show() if fail_nodes:
markup = "\n".join(map(lambda n: n.name, fail_nodes))
markup = "\n".join(map(lambda n: "%s via %s" % (n.name, ifaces.get(n.iface, n.iface)), fail_nodes)) buf = gtk.TextBuffer() buf.set_text(markup) w_fail.show()
diff --git a/partIntfHelpers.py b/partIntfHelpers.py index c17945b..9ce4afc 100644 --- a/partIntfHelpers.py +++ b/partIntfHelpers.py @@ -412,7 +412,8 @@ class iSCSIWizard(): pass
@abstractmethod
- def display_success_dialog(self, success_nodes, fail_nodes, fail_reason):
def display_success_dialog(self, success_nodes, fail_nodes, fail_reason,
ifaces): pass
@abstractmethod
@@ -497,7 +498,8 @@ def drive_iscsi_addition(anaconda, wizard): elif step == STEP_SUMMARY: rc = wizard.display_success_dialog(login_ok_nodes, login_fail_nodes,
login_fail_msg)
login_fail_msg,
anaconda.id.storage.iscsi.ifaces) if rc: step = STEP_STABILIZE else:
diff --git a/textw/add_drive_text.py b/textw/add_drive_text.py index 8ba4da4..e196e2f 100644 --- a/textw/add_drive_text.py +++ b/textw/add_drive_text.py @@ -229,7 +229,8 @@ class iSCSITextWizard(pih.iSCSIWizard): if i in listbox.getSelection()] return (rc, selected_nodes)
- def display_success_dialog(self, success_nodes, fail_nodes, fail_reason):
- def display_success_dialog(self, success_nodes, fail_nodes, fail_reason,
ifaces): buttons = [TEXT_OK_BUTTON] msg = _("Successfully logged into all the selected nodes.") msg_reason = _("Reason:")
-- 1.7.4
Anaconda-devel-list mailing list Anaconda-devel-list@redhat.com https://www.redhat.com/mailman/listinfo/anaconda-devel-list
Useful for bringing up second interface for iscsi (e.g. for iface bound and multipathed target)
Related: rhbz#500273 --- iw/advanced_storage.py | 12 +++++ iw/network_gui.py | 13 ++++-- ui/adddrive.glade | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 5 deletions(-)
diff --git a/iw/advanced_storage.py b/iw/advanced_storage.py index 35e8a92..928a891 100644 --- a/iw/advanced_storage.py +++ b/iw/advanced_storage.py @@ -479,6 +479,18 @@ def addDrive(anaconda): dxml.get_widget("fcoeRadio").set_sensitive(False) dxml.get_widget("fcoeRadio").set_active(False)
+ def update_active_ifaces(): + active_ifaces = network.getActiveNetDevs() + dxml.get_widget("ifaceLabel").set_text(", ".join(active_ifaces)) + + def netconfButton_clicked(*args): + from network_gui import setupNetwork + setupNetwork(anaconda.intf) + update_active_ifaces() + + dxml.get_widget("netconfButton").connect("clicked", netconfButton_clicked) + update_active_ifaces() + #figure out what advanced devices we have available and set sensible default group = dxml.get_widget("iscsiRadio").get_group() for button in group: diff --git a/iw/network_gui.py b/iw/network_gui.py index 702d227..31ec0c5 100644 --- a/iw/network_gui.py +++ b/iw/network_gui.py @@ -50,7 +50,7 @@ class NetworkWindow(InstallWindow): self.hostnameEntry.set_text(self.hostname)
self.netconfButton = self.xml.get_widget("netconfButton") - self.netconfButton.connect("clicked", self._setupNetwork) + self.netconfButton.connect("clicked", self._netconfButton_clicked) if len(self.anaconda.id.network.netdevices) == 0: self.netconfButton.set_sensitive(False)
@@ -63,10 +63,8 @@ class NetworkWindow(InstallWindow):
return self.align
- def _setupNetwork(self, *args): - self.intf.enableNetwork(just_setup=True) - if network.hasActiveNetDev(): - urlgrabber.grabber.reset_curl_obj() + def _netconfButton_clicked(self, *args): + setupNetwork(self.intf)
def focus(self): self.hostnameEntry.grab_focus() @@ -98,6 +96,11 @@ class NetworkWindow(InstallWindow): self.anaconda.id.network.setHostname(hostname) return None
+def setupNetwork(intf): + intf.enableNetwork(just_setup=True) + if network.hasActiveNetDev(): + urlgrabber.grabber.reset_curl_obj() + def NMCEExited(pid, condition, anaconda): if anaconda: anaconda.intf.icw.window.set_sensitive(True) diff --git a/ui/adddrive.glade b/ui/adddrive.glade index 5440966..84f9dd2 100644 --- a/ui/adddrive.glade +++ b/ui/adddrive.glade @@ -260,6 +260,113 @@ <property name="fill">True</property> </packing> </child> + + <child> + <widget class="GtkHSeparator" id="hseparator1"> + <property name="visible">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">7</property> + + <child> + <widget class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="label" translatable="yes">Active network interfaces:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="ifaceLabel"> + <property name="visible">True</property> + <property name="label" translatable="yes">None</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox3"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <placeholder/> + </child> + + <child> + <widget class="GtkButton" id="netconfButton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">C_onfigure Network</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> </widget> <packing> <property name="padding">0</property>
Ack.
On Tue, Feb 28, 2012 at 12:03:32PM +0100, Radek Vykydal wrote:
Useful for bringing up second interface for iscsi (e.g. for iface bound and multipathed target)
Related: rhbz#500273
iw/advanced_storage.py | 12 +++++ iw/network_gui.py | 13 ++++-- ui/adddrive.glade | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 5 deletions(-)
diff --git a/iw/advanced_storage.py b/iw/advanced_storage.py index 35e8a92..928a891 100644 --- a/iw/advanced_storage.py +++ b/iw/advanced_storage.py @@ -479,6 +479,18 @@ def addDrive(anaconda): dxml.get_widget("fcoeRadio").set_sensitive(False) dxml.get_widget("fcoeRadio").set_active(False)
- def update_active_ifaces():
active_ifaces = network.getActiveNetDevs()
dxml.get_widget("ifaceLabel").set_text(", ".join(active_ifaces))
- def netconfButton_clicked(*args):
from network_gui import setupNetwork
setupNetwork(anaconda.intf)
update_active_ifaces()
- dxml.get_widget("netconfButton").connect("clicked", netconfButton_clicked)
- update_active_ifaces()
- #figure out what advanced devices we have available and set sensible default group = dxml.get_widget("iscsiRadio").get_group() for button in group:
diff --git a/iw/network_gui.py b/iw/network_gui.py index 702d227..31ec0c5 100644 --- a/iw/network_gui.py +++ b/iw/network_gui.py @@ -50,7 +50,7 @@ class NetworkWindow(InstallWindow): self.hostnameEntry.set_text(self.hostname)
self.netconfButton = self.xml.get_widget("netconfButton")
self.netconfButton.connect("clicked", self._setupNetwork)
self.netconfButton.connect("clicked", self._netconfButton_clicked) if len(self.anaconda.id.network.netdevices) == 0: self.netconfButton.set_sensitive(False)
@@ -63,10 +63,8 @@ class NetworkWindow(InstallWindow):
return self.align
- def _setupNetwork(self, *args):
self.intf.enableNetwork(just_setup=True)
if network.hasActiveNetDev():
urlgrabber.grabber.reset_curl_obj()
def _netconfButton_clicked(self, *args):
setupNetwork(self.intf)
def focus(self): self.hostnameEntry.grab_focus()
@@ -98,6 +96,11 @@ class NetworkWindow(InstallWindow): self.anaconda.id.network.setHostname(hostname) return None
+def setupNetwork(intf):
- intf.enableNetwork(just_setup=True)
- if network.hasActiveNetDev():
urlgrabber.grabber.reset_curl_obj()
def NMCEExited(pid, condition, anaconda): if anaconda: anaconda.intf.icw.window.set_sensitive(True) diff --git a/ui/adddrive.glade b/ui/adddrive.glade index 5440966..84f9dd2 100644 --- a/ui/adddrive.glade +++ b/ui/adddrive.glade @@ -260,6 +260,113 @@ <property name="fill">True</property> </packing> </child>
<child>
<widget class="GtkHSeparator" id="hseparator1">
<property name="visible">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">7</property>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="label" translatable="yes">Active network interfaces:</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="ifaceLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">None</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox3">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<placeholder/>
</child>
<child>
<widget class="GtkButton" id="netconfButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">C_onfigure Network</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget> <packing> <property name="padding">0</property>
-- 1.7.4
Anaconda-devel-list mailing list Anaconda-devel-list@redhat.com https://www.redhat.com/mailman/listinfo/anaconda-devel-list
Resolves: rhbz#500273
All devices must be either bonded (using --iface option) or using default. --- kickstart.py | 24 ++++++++++++++++++++---- storage/iscsi.py | 10 +++++++++- 2 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/kickstart.py b/kickstart.py index de2dbe9..2c52854 100644 --- a/kickstart.py +++ b/kickstart.py @@ -415,16 +415,32 @@ class IgnoreDisk(commands.ignoredisk.RHEL6_IgnoreDisk): else: anaconda.id.ksdata.skipSteps.extend(["filter", "filtertype"])
-class Iscsi(commands.iscsi.F10_Iscsi): +class Iscsi(commands.iscsi.RHEL6_Iscsi): def parse(self, args): - tg = commands.iscsi.F10_Iscsi.parse(self, args) + tg = commands.iscsi.RHEL6_Iscsi.parse(self, args) + + if tg.iface: + active_ifaces = network.getActiveNetDevs() + if tg.iface not in active_ifaces: + raise KickstartValueError, formatErrorMsg(self.lineno, msg="network interface %s required by iscsi %s target is not up" % (tg.iface, tg.target)) + + mode = storage.iscsi.iscsi().mode + if mode == "none": + if tg.iface: + storage.iscsi.iscsi().create_interfaces(active_ifaces) + elif ((mode == "bind" and not tg.iface) + or (mode == "default" and tg.iface)): + raise KickstartValueError, formatErrorMsg(self.lineno, msg="iscsi --iface must be specified (binding used) either for all targets or for none")
try: storage.iscsi.iscsi().addTarget(tg.ipaddr, tg.port, tg.user, tg.password, tg.user_in, tg.password_in, - target=tg.target) - log.info("added iscsi target: %s" %(tg.ipaddr,)) + target=tg.target, + iface=tg.iface) + log.info("added iscsi target %s at %s via %s" %(tg.target, + tg.ipaddr, + tg.iface)) except (IOError, ValueError), e: raise KickstartValueError, formatErrorMsg(self.lineno, msg=str(e)) diff --git a/storage/iscsi.py b/storage/iscsi.py index 34c4ad0..7e93113 100644 --- a/storage/iscsi.py +++ b/storage/iscsi.py @@ -369,7 +369,7 @@ class iscsi(object): # NOTE: the same credentials are used for discovery and login # (unlike in UI) def addTarget(self, ipaddr, port="3260", user=None, pw=None, - user_in=None, pw_in=None, intf=None, target=None): + user_in=None, pw_in=None, intf=None, target=None, iface=None): found = 0 logged_in = 0
@@ -383,6 +383,12 @@ class iscsi(object): log.debug("iscsi: skipping logging to iscsi node '%s'" % node.name) continue + if iface: + node_net_iface = self.ifaces.get(node.iface, node.iface) + if iface != node_net_iface: + log.debug("iscsi: skipping logging to iscsi node '%s' via %s" % + (node.name, node_net_iface)) + continue
found = found + 1
@@ -406,6 +412,8 @@ class iscsi(object): for n in self.active_nodes(): f.write("iscsi --ipaddr %s --port %s --target %s" % (n.address, n.port, n.name)) + if n.iface != "default": + f.write(" --iface %s" % self.ifaces[n.iface]) auth = n.getAuth() if auth: f.write(" --user %s" % auth.username)
Ack.
On Tue, Feb 28, 2012 at 12:03:33PM +0100, Radek Vykydal wrote:
Resolves: rhbz#500273
All devices must be either bonded (using --iface option) or using default.
kickstart.py | 24 ++++++++++++++++++++---- storage/iscsi.py | 10 +++++++++- 2 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/kickstart.py b/kickstart.py index de2dbe9..2c52854 100644 --- a/kickstart.py +++ b/kickstart.py @@ -415,16 +415,32 @@ class IgnoreDisk(commands.ignoredisk.RHEL6_IgnoreDisk): else: anaconda.id.ksdata.skipSteps.extend(["filter", "filtertype"])
-class Iscsi(commands.iscsi.F10_Iscsi): +class Iscsi(commands.iscsi.RHEL6_Iscsi): def parse(self, args):
tg = commands.iscsi.F10_Iscsi.parse(self, args)
tg = commands.iscsi.RHEL6_Iscsi.parse(self, args)
if tg.iface:
active_ifaces = network.getActiveNetDevs()
if tg.iface not in active_ifaces:
raise KickstartValueError, formatErrorMsg(self.lineno, msg="network interface %s required by iscsi %s target is not up" % (tg.iface, tg.target))
mode = storage.iscsi.iscsi().mode
if mode == "none":
if tg.iface:
storage.iscsi.iscsi().create_interfaces(active_ifaces)
elif ((mode == "bind" and not tg.iface)
or (mode == "default" and tg.iface)):
raise KickstartValueError, formatErrorMsg(self.lineno, msg="iscsi --iface must be specified (binding used) either for all targets or for none") try: storage.iscsi.iscsi().addTarget(tg.ipaddr, tg.port, tg.user, tg.password, tg.user_in, tg.password_in,
target=tg.target)
log.info("added iscsi target: %s" %(tg.ipaddr,))
target=tg.target,
iface=tg.iface)
log.info("added iscsi target %s at %s via %s" %(tg.target,
tg.ipaddr,
tg.iface)) except (IOError, ValueError), e: raise KickstartValueError, formatErrorMsg(self.lineno, msg=str(e))
diff --git a/storage/iscsi.py b/storage/iscsi.py index 34c4ad0..7e93113 100644 --- a/storage/iscsi.py +++ b/storage/iscsi.py @@ -369,7 +369,7 @@ class iscsi(object): # NOTE: the same credentials are used for discovery and login # (unlike in UI) def addTarget(self, ipaddr, port="3260", user=None, pw=None,
user_in=None, pw_in=None, intf=None, target=None):
user_in=None, pw_in=None, intf=None, target=None, iface=None): found = 0 logged_in = 0
@@ -383,6 +383,12 @@ class iscsi(object): log.debug("iscsi: skipping logging to iscsi node '%s'" % node.name) continue
if iface:
node_net_iface = self.ifaces.get(node.iface, node.iface)
if iface != node_net_iface:
log.debug("iscsi: skipping logging to iscsi node '%s' via %s" %
(node.name, node_net_iface))
continue found = found + 1
@@ -406,6 +412,8 @@ class iscsi(object): for n in self.active_nodes(): f.write("iscsi --ipaddr %s --port %s --target %s" % (n.address, n.port, n.name))
if n.iface != "default":
f.write(" --iface %s" % self.ifaces[n.iface]) auth = n.getAuth() if auth: f.write(" --user %s" % auth.username)
-- 1.7.4
Anaconda-devel-list mailing list Anaconda-devel-list@redhat.com https://www.redhat.com/mailman/listinfo/anaconda-devel-list
Resolves: rhbz#500273
In this initial support all used nodes will be either iface bound using default iface. --- textw/add_drive_text.py | 32 ++++++++++++++++++++++++++------ 1 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/textw/add_drive_text.py b/textw/add_drive_text.py index e196e2f..0a2890a 100644 --- a/textw/add_drive_text.py +++ b/textw/add_drive_text.py @@ -187,7 +187,7 @@ class iSCSITextWizard(pih.iSCSIWizard): # should never stop us: return True
- def display_nodes_dialog(self, found_nodes, iscsi_ifaces): + def display_nodes_dialog(self, found_nodes, ifaces): grid_height = 4 basic_grid = None if self.listbox_login.current() not in \ @@ -210,7 +210,10 @@ class iSCSITextWizard(pih.iSCSIWizard): # unfortunately, Listbox.add won't accept node directly as the second # argument, we have to remember the list and use an index for i, node in enumerate(found_nodes): - listbox.append(node.name, i, selected=True) + node_description = "%s via %s" % (node.name, + ifaces.get(node.iface, + node.iface)) + listbox.append(node_description, i, selected=True) grid.add(listbox, 0, 1, padding=(0, 1, 0, 1))
if basic_grid: @@ -295,7 +298,14 @@ class addDriveDialog(object): def addDriveDialog(self, screen): newdrv = [] if storage.iscsi.has_iscsi(): - newdrv.append("Add iSCSI target") + if storage.iscsi.iscsi().mode == "none": + newdrv.append("Add iSCSI target") + newdrv.append("Add iSCSI target - use interface binding") + elif storage.iscsi.iscsi().mode == "bind": + newdrv.append("Add iSCSI target - use interface binding") + elif storage.iscsi.iscsi().mode == "default": + newdrv.append("Add iSCSI target") + if iutil.isS390(): newdrv.append( "Add zFCP LUN" ) if storage.fcoe.has_fcoe(): @@ -326,9 +336,10 @@ class addDriveDialog(object): except ValueError, e: ButtonChoiceWindow(screen, _("Error"), str(e)) return INSTALL_BACK - else: + elif newdrv[choice].startswith("Add iSCSI target"): + bind = newdrv[choice] == "Add iSCSI target - use interface binding" try: - return self.addIscsiDriveDialog(screen) + return self.addIscsiDriveDialog(screen, bind) except (ValueError, IOError), e: ButtonChoiceWindow(screen, _("Error"), str(e)) return INSTALL_BACK @@ -402,7 +413,7 @@ class addDriveDialog(object): screen.popWindow() return INSTALL_OK
- def addIscsiDriveDialog(self, screen): + def addIscsiDriveDialog(self, screen, bind=False): if not network.hasActiveNetDev(): ButtonChoiceWindow(screen, _("Error"), "Must have a network configuration set up " @@ -411,6 +422,15 @@ class addDriveDialog(object): log.info("addIscsiDriveDialog(): early exit, network disabled.") return INSTALL_BACK
+ # This will modify behaviour of iscsi.discovery() function + if storage.iscsi.iscsi().mode == "none" and not bind: + storage.iscsi.iscsi().delete_interfaces() + elif (storage.iscsi.iscsi().mode == "none" and bind + or storage.iscsi.iscsi().mode == "bind"): + active = set(network.getActiveNetDevs()) + created = set(storage.iscsi.iscsi().ifaces.values()) + storage.iscsi.iscsi().create_interfaces(active - created) + wizard = iSCSITextWizard(screen) login_ok_nodes = pih.drive_iscsi_addition(self.anaconda, wizard) if len(login_ok_nodes):
Ack, with comments.
On Tue, Feb 28, 2012 at 12:03:34PM +0100, Radek Vykydal wrote:
Resolves: rhbz#500273
In this initial support all used nodes will be either iface bound using default iface.
textw/add_drive_text.py | 32 ++++++++++++++++++++++++++------ 1 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/textw/add_drive_text.py b/textw/add_drive_text.py index e196e2f..0a2890a 100644 --- a/textw/add_drive_text.py +++ b/textw/add_drive_text.py @@ -187,7 +187,7 @@ class iSCSITextWizard(pih.iSCSIWizard): # should never stop us: return True
- def display_nodes_dialog(self, found_nodes, iscsi_ifaces):
- def display_nodes_dialog(self, found_nodes, ifaces): grid_height = 4 basic_grid = None if self.listbox_login.current() not in \
@@ -210,7 +210,10 @@ class iSCSITextWizard(pih.iSCSIWizard): # unfortunately, Listbox.add won't accept node directly as the second # argument, we have to remember the list and use an index for i, node in enumerate(found_nodes):
listbox.append(node.name, i, selected=True)
node_description = "%s via %s" % (node.name,
ifaces.get(node.iface,
node.iface))
listbox.append(node_description, i, selected=True) grid.add(listbox, 0, 1, padding=(0, 1, 0, 1)) if basic_grid:
@@ -295,7 +298,14 @@ class addDriveDialog(object): def addDriveDialog(self, screen): newdrv = [] if storage.iscsi.has_iscsi():
newdrv.append("Add iSCSI target")
if storage.iscsi.iscsi().mode == "none":
newdrv.append("Add iSCSI target")
newdrv.append("Add iSCSI target - use interface binding")
elif storage.iscsi.iscsi().mode == "bind":
newdrv.append("Add iSCSI target - use interface binding")
elif storage.iscsi.iscsi().mode == "default":
newdrv.append("Add iSCSI target")
if iutil.isS390(): newdrv.append( "Add zFCP LUN" ) if storage.fcoe.has_fcoe():
@@ -326,9 +336,10 @@ class addDriveDialog(object): except ValueError, e: ButtonChoiceWindow(screen, _("Error"), str(e)) return INSTALL_BACK
else:
elif newdrv[choice].startswith("Add iSCSI target"):
bind = newdrv[choice] == "Add iSCSI target - use interface binding" try:
return self.addIscsiDriveDialog(screen)
return self.addIscsiDriveDialog(screen, bind) except (ValueError, IOError), e: ButtonChoiceWindow(screen, _("Error"), str(e)) return INSTALL_BACK
@@ -402,7 +413,7 @@ class addDriveDialog(object): screen.popWindow() return INSTALL_OK
- def addIscsiDriveDialog(self, screen):
- def addIscsiDriveDialog(self, screen, bind=False): if not network.hasActiveNetDev(): ButtonChoiceWindow(screen, _("Error"), "Must have a network configuration set up "
@@ -411,6 +422,15 @@ class addDriveDialog(object): log.info("addIscsiDriveDialog(): early exit, network disabled.") return INSTALL_BACK
# This will modify behaviour of iscsi.discovery() function
if storage.iscsi.iscsi().mode == "none" and not bind:
storage.iscsi.iscsi().delete_interfaces()
elif (storage.iscsi.iscsi().mode == "none" and bind
or storage.iscsi.iscsi().mode == "bind"):
Same comment from the other patch.
active = set(network.getActiveNetDevs())
created = set(storage.iscsi.iscsi().ifaces.values())
storage.iscsi.iscsi().create_interfaces(active - created)
wizard = iSCSITextWizard(screen) login_ok_nodes = pih.drive_iscsi_addition(self.anaconda, wizard) if len(login_ok_nodes):
-- 1.7.4
Anaconda-devel-list mailing list Anaconda-devel-list@redhat.com https://www.redhat.com/mailman/listinfo/anaconda-devel-list
iscsi --iface=eth0
Resolves: rhbz#500273 --- pykickstart/commands/iscsi.py | 26 ++++++++++++++++++++++++++ pykickstart/handlers/control.py | 4 ++-- tests/commands/iscsi.py | 5 +++++ 3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/pykickstart/commands/iscsi.py b/pykickstart/commands/iscsi.py index da5a544..944f13c 100644 --- a/pykickstart/commands/iscsi.py +++ b/pykickstart/commands/iscsi.py @@ -77,6 +77,22 @@ class F10_IscsiData(FC6_IscsiData):
return retval
+class RHEL6_IscsiData(F10_IscsiData): + removedKeywords = F10_IscsiData.removedKeywords + removedAttrs = F10_IscsiData.removedAttrs + + def __init__(self, *args, **kwargs): + F10_IscsiData.__init__(self, *args, **kwargs) + self.iface = kwargs.get("iface", None) + + def _getArgsAsStr(self): + retval = F10_IscsiData._getArgsAsStr(self) + + if self.iface is not None: + retval += " --iface=%s" % self.iface + + return retval + class FC6_Iscsi(KickstartCommand): removedKeywords = KickstartCommand.removedKeywords removedAttrs = KickstartCommand.removedAttrs @@ -131,3 +147,13 @@ class F10_Iscsi(FC6_Iscsi): op.add_option("--reverse-password", dest="password_in", action="store", type="string") return op + +class RHEL6_Iscsi(F10_Iscsi): + removedKeywords = F10_Iscsi.removedKeywords + removedAttrs = F10_Iscsi.removedAttrs + + def _getParser(self): + op = F10_Iscsi._getParser(self) + op.add_option("--iface", dest="iface", action="store", + type="string") + return op diff --git a/pykickstart/handlers/control.py b/pykickstart/handlers/control.py index e89d10c..ec7cf22 100644 --- a/pykickstart/handlers/control.py +++ b/pykickstart/handlers/control.py @@ -833,7 +833,7 @@ commandMap = { "ignoredisk": ignoredisk.RHEL6_IgnoreDisk, "install": upgrade.F11_Upgrade, "interactive": interactive.FC3_Interactive, - "iscsi": iscsi.F10_Iscsi, + "iscsi": iscsi.RHEL6_Iscsi, "iscsiname": iscsiname.FC6_IscsiName, "key": key.F7_Key, "keyboard": keyboard.FC3_Keyboard, @@ -1067,7 +1067,7 @@ dataMap = { "DmRaidData": dmraid.FC6_DmRaidData, "FcoeData": fcoe.F13_FcoeData, "GroupData": group.F12_GroupData, - "IscsiData": iscsi.F10_IscsiData, + "IscsiData": iscsi.RHEL6_IscsiData, "LogVolData": logvol.F12_LogVolData, "MultiPathData": multipath.FC6_MultiPathData, "NetworkData": network.RHEL6_NetworkData, diff --git a/tests/commands/iscsi.py b/tests/commands/iscsi.py index 6bf312a..7abfea2 100644 --- a/tests/commands/iscsi.py +++ b/tests/commands/iscsi.py @@ -65,6 +65,11 @@ class F10_TestCase(FC6_TestCase): self.assert_parse_error("iscsi --ipaddr=1.1.1.1 --reverse-user", KickstartParseError) self.assert_parse_error("iscsi --ipaddr=1.1.1.1 --reverse-password", KickstartParseError)
+class RHEL6_TestCase(F10_TestCase): + def runTest(self): + F10_TestCase.runTest(self) + + self.assert_parse("iscsi --ipaddr=1.1.1.1 --iface=eth0\n")
if __name__ == "__main__": unittest.main()
Ack.
On Tue, Feb 28, 2012 at 12:03:35PM +0100, Radek Vykydal wrote:
iscsi --iface=eth0
Resolves: rhbz#500273
pykickstart/commands/iscsi.py | 26 ++++++++++++++++++++++++++ pykickstart/handlers/control.py | 4 ++-- tests/commands/iscsi.py | 5 +++++ 3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/pykickstart/commands/iscsi.py b/pykickstart/commands/iscsi.py index da5a544..944f13c 100644 --- a/pykickstart/commands/iscsi.py +++ b/pykickstart/commands/iscsi.py @@ -77,6 +77,22 @@ class F10_IscsiData(FC6_IscsiData):
return retval
+class RHEL6_IscsiData(F10_IscsiData):
- removedKeywords = F10_IscsiData.removedKeywords
- removedAttrs = F10_IscsiData.removedAttrs
- def __init__(self, *args, **kwargs):
F10_IscsiData.__init__(self, *args, **kwargs)
self.iface = kwargs.get("iface", None)
- def _getArgsAsStr(self):
retval = F10_IscsiData._getArgsAsStr(self)
if self.iface is not None:
retval += " --iface=%s" % self.iface
return retval
class FC6_Iscsi(KickstartCommand): removedKeywords = KickstartCommand.removedKeywords removedAttrs = KickstartCommand.removedAttrs @@ -131,3 +147,13 @@ class F10_Iscsi(FC6_Iscsi): op.add_option("--reverse-password", dest="password_in", action="store", type="string") return op
+class RHEL6_Iscsi(F10_Iscsi):
- removedKeywords = F10_Iscsi.removedKeywords
- removedAttrs = F10_Iscsi.removedAttrs
- def _getParser(self):
op = F10_Iscsi._getParser(self)
op.add_option("--iface", dest="iface", action="store",
type="string")
return op
diff --git a/pykickstart/handlers/control.py b/pykickstart/handlers/control.py index e89d10c..ec7cf22 100644 --- a/pykickstart/handlers/control.py +++ b/pykickstart/handlers/control.py @@ -833,7 +833,7 @@ commandMap = { "ignoredisk": ignoredisk.RHEL6_IgnoreDisk, "install": upgrade.F11_Upgrade, "interactive": interactive.FC3_Interactive,
"iscsi": iscsi.F10_Iscsi,
"iscsi": iscsi.RHEL6_Iscsi, "iscsiname": iscsiname.FC6_IscsiName, "key": key.F7_Key, "keyboard": keyboard.FC3_Keyboard,
@@ -1067,7 +1067,7 @@ dataMap = { "DmRaidData": dmraid.FC6_DmRaidData, "FcoeData": fcoe.F13_FcoeData, "GroupData": group.F12_GroupData,
"IscsiData": iscsi.F10_IscsiData,
"IscsiData": iscsi.RHEL6_IscsiData, "LogVolData": logvol.F12_LogVolData, "MultiPathData": multipath.FC6_MultiPathData, "NetworkData": network.RHEL6_NetworkData,
diff --git a/tests/commands/iscsi.py b/tests/commands/iscsi.py index 6bf312a..7abfea2 100644 --- a/tests/commands/iscsi.py +++ b/tests/commands/iscsi.py @@ -65,6 +65,11 @@ class F10_TestCase(FC6_TestCase): self.assert_parse_error("iscsi --ipaddr=1.1.1.1 --reverse-user", KickstartParseError) self.assert_parse_error("iscsi --ipaddr=1.1.1.1 --reverse-password", KickstartParseError)
+class RHEL6_TestCase(F10_TestCase):
- def runTest(self):
F10_TestCase.runTest(self)
self.assert_parse("iscsi --ipaddr=1.1.1.1 --iface=eth0\n")
if __name__ == "__main__": unittest.main() -- 1.7.4
Anaconda-devel-list mailing list Anaconda-devel-list@redhat.com https://www.redhat.com/mailman/listinfo/anaconda-devel-list
iscsi --iface=eth0
Resolves: rhbz#500273
pykickstart/commands/iscsi.py | 26 ++++++++++++++++++++++++++ pykickstart/handlers/control.py | 4 ++-- tests/commands/iscsi.py | 5 +++++ 3 files changed, 33 insertions(+), 2 deletions(-)
Please make sure to put this patch on master as well so master knows that this syntax was supported in RHEL6. Thanks.
- Chris
anaconda-devel@lists.stg.fedoraproject.org