[master 6/9] iscsi: allow separate discovery/login credentials in TUI.

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

 



TUI now utilizes the same "controller" that drives the GUI part:
partIntfHelper.drive_iscsi_addition(). This saves code duplication, the
only thing that had to be implemented was the TUI iscsi wizard.

See 8123165b3163b4a70066b11091ac309cc91c4cb8 with the same functionality
for GUI.

Related: rhbz#607827
Related: rhbz#469382
---
 pyanaconda/textw/add_drive_text.py |  307 ++++++++++++++++++++++++++++++-----
 pyanaconda/textw/constants_text.py |    4 +
 2 files changed, 267 insertions(+), 44 deletions(-)

diff --git a/pyanaconda/textw/add_drive_text.py b/pyanaconda/textw/add_drive_text.py
index 76c8c24..86f1571 100644
--- a/pyanaconda/textw/add_drive_text.py
+++ b/pyanaconda/textw/add_drive_text.py
@@ -23,6 +23,7 @@ from pyanaconda.storage import zfcp
 from snack import *
 from constants_text import *
 from pyanaconda.constants import *
+import pyanaconda.partIntfHelpers as pih 
 
 import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
@@ -30,6 +31,262 @@ _ = lambda x: gettext.ldgettext("anaconda", x)
 import logging
 log = logging.getLogger("anaconda")
 
+# iSCSI Wizard classes and helpers
+
+class GridEntry(object):
+    def __init__(self, text, disabled=False, password=False, width=20):
+        self.text = text
+        self.disabled = disabled
+        self.password = password
+        self.width = width
+
+class iSCSITextWizard(pih.iSCSIWizard):
+    def __init__(self, screen):
+        self.screen = screen
+        self.entry_target_ip = None
+        self.entry_initiator = None
+        self.entry_disc_username = None
+        self.entry_disc_password = None
+        self.entry_disc_r_username = None
+        self.entry_disc_r_password = None
+        self.entry_login_username = None
+        self.entry_login_password = None
+        self.entry_login_r_username = None
+        self.entry_login_r_password = None
+        self.listbox_disc = None
+        self.listbox_login = None
+        self.listbox_nodes = None
+
+    @staticmethod
+    def _auth_entries(cred_type):
+        all_entries = [
+                GridEntry(_("CHAP Username:")),
+                GridEntry(_("CHAP Password:"), password=True),
+                GridEntry(_("Reverse CHAP Username:")),
+                GridEntry(_("Reverse CHAP Password:"), password=True)
+                ]
+
+        entries = [None for i in range(4)]
+        if cred_type == pih.CRED_ONE[0]:
+            entries = all_entries[0:2] + [None for i in range(2)]
+        elif cred_type == pih.CRED_BOTH[0]:
+            entries = all_entries
+        return entries
+
+    @staticmethod
+    def _build_grid(grid_entries):
+        entries = []
+        grid = Grid(2, len(grid_entries))
+        for (i, ge) in enumerate(grid_entries):
+            if ge:
+                grid.setField(Label(ge.text), 0, i)
+                entry = Entry(ge.width, password=ge.password)
+                if ge.disabled:
+                    entry.setFlags(FLAG_DISABLED, FLAGS_SET)
+                grid.setField(entry, 1, i)
+            else:
+                entry = None
+            # we want Nones in grid_entries result in Nones in return value
+            entries.append(entry)
+        return (grid, entries)
+
+    @staticmethod
+    def _value_when(entry):
+        return entry.value() if entry else None
+    
+    def _discovery_auth_dialog(self):
+        if self.listbox_disc.current() == pih.CRED_NONE[0]:
+            # we need not collect anything
+            return True
+
+        grid = GridForm(self.screen, _("iSCSI Discovery Credentials"), 1, 3)
+        grid.add(TextboxReflowed(50,
+                                 _("Please enter the iSCSI "
+                                   "discovery credentials.")),
+                 0, 0)
+        auth_entries = self._auth_entries(self.listbox_disc.current())
+        (basic_grid, entries) = self._build_grid(auth_entries)
+        (self.entry_disc_username,
+         self.entry_disc_password,
+         self.entry_disc_r_username,
+         self.entry_disc_r_password) = entries
+         
+        grid.add(basic_grid, 0, 1, padding=(0, 1, 0, 1))
+
+        grid.buttons = ButtonBar(self.screen, 
+                                 [TEXT_OK_BUTTON,TEXT_CANCEL_BUTTON])
+        grid.add(grid.buttons, 0, 2, padding=(0, 1, 0, -1))
+
+        return self._run_grid(grid)
+
+    def _discovery_setup_dialog(self, initiator, initiator_set):
+        grid = GridForm(self.screen, _("iSCSI Discovery"), 1, 7)
+        header_text = TextboxReflowed(60,
+                                      _("To use iSCSI disks, you must provide "
+                                        "the address of your iSCSI target and "
+                                        "the iSCSI initiator name you've "
+                                        "configured for your host."))
+        grid.add(header_text, 0, 0)
+        
+        entry_list = [
+            GridEntry(_("Target IP Address:"), width=40),
+            GridEntry(_("iSCSI Initiator Name:"), 
+                      disabled=initiator_set, 
+                      width=40)
+            ]
+        (basic_grid, (self.entry_target_ip, self.entry_initiator)) = \
+            self._build_grid(entry_list)
+        self.entry_initiator.set(initiator)
+        grid.add(basic_grid, 0, 1)
+
+        grid.add(TextboxReflowed(60,
+                                 _("What kind of iSCSI discovery "
+                                   "authentication you wish to perform:")), 
+                 0, 2, padding=(0, 1, 0, 0))
+        
+        self.listbox_disc = Listbox(3, scroll=1)
+        self.listbox_disc.append(*reversed(pih.CRED_NONE))
+        self.listbox_disc.append(*reversed(pih.CRED_ONE))
+        self.listbox_disc.append(*reversed(pih.CRED_BOTH))
+        grid.add(self.listbox_disc, 0, 3)
+
+        grid.add(TextboxReflowed(60,
+                                 _("What kind of iSCSI login authentication "
+                                   "you wish to perform:")), 
+                 0, 4, padding=(0, 1, 0, 0))
+
+        self.listbox_login = Listbox(3, scroll=1)
+        self.listbox_login.append(*reversed(pih.CRED_NONE))
+        self.listbox_login.append(*reversed(pih.CRED_ONE))
+        self.listbox_login.append(*reversed(pih.CRED_BOTH))
+        self.listbox_login.append(*reversed(pih.CRED_REUSE))
+        grid.add(self.listbox_login, 0, 5)
+
+        grid.buttons = ButtonBar(self.screen,
+                                 [TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON])
+        grid.add(grid.buttons, 0, 6, padding=(0, 1, 0, -1))
+        
+        return self._run_grid(grid)
+
+    def _run_grid(self, grid):
+        result = grid.run()
+        button = grid.buttons.buttonPressed(result)
+        self.screen.popWindow()
+        return True if button == TEXT_OK_CHECK else False
+
+    def destroy_dialogs(self):
+        pass
+
+    def display_discovery_dialog(self, initiator, initiator_set):
+        # this is in fact two dialogs here due to limited screen space in TUI
+        return self._discovery_setup_dialog(initiator, initiator_set) and \
+            self._discovery_auth_dialog()
+
+    def display_login_dialog(self):
+        # in TUI, the login credentials are asked for with nodes list, so this
+        # should never stop us:
+        return True
+
+    def display_nodes_dialog(self, found_nodes):
+        grid_height = 4
+        basic_grid = None
+        if self.listbox_login.current() not in \
+                (pih.CRED_NONE[0], pih.CRED_REUSE[0]):
+            auth_entries = self._auth_entries(self.listbox_login.current())
+            (basic_grid, entries) = self._build_grid(auth_entries)
+            (self.entry_login_username,
+             self.entry_login_password,
+             self.entry_login_r_username,
+             self.entry_login_r_password) = entries
+
+            grid_height += 1
+
+        grid = GridForm(self.screen, _("iSCSI Discovered Nodes"), 1, 5)
+        grid.add(TextboxReflowed(50,
+                                 _("Check the nodes you wish to log into:")),
+                 0, 0)
+
+        listbox = CheckboxTree(5, scroll=1)
+        # 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)
+        grid.add(listbox, 0, 1, padding=(0, 1, 0, 1))
+
+        if basic_grid:
+            grid.add(TextboxReflowed(60,
+                                     _("Please enter iSCSI login credentials "
+                                       "for the selected nodes:")),
+                     0, 2)
+            grid.add(basic_grid, 0, 3, padding=(0, 1, 0, 1))
+
+        grid.buttons = ButtonBar(self.screen, 
+                                 [TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON])
+        grid.add(grid.buttons, 0, 4, padding=(0, 0, 0, -1))
+
+        rc = self._run_grid(grid)
+        selected_nodes = [node for (i, node) in enumerate(found_nodes)
+                          if i in listbox.getSelection()]
+        return (rc, selected_nodes)
+
+    def display_success_dialog(self, success_nodes, fail_nodes, fail_reason):
+        buttons = [TEXT_OK_BUTTON]
+        msg = _("Successfully logged into all the selected nodes.")
+        msg_reason = _("Reason:")
+        if fail_nodes:
+            buttons.append(TEXT_RETRY_BUTTON)
+            msg = _("Could not log into the following nodes:\n")
+            msg = reduce(lambda s1, s2: "%s\n%s" % (s1, s2), fail_nodes, msg)
+        if fail_reason:
+            msg = "%s\n\n%s\n%s" % (msg, msg_reason, fail_reason)
+
+        rc = ButtonChoiceWindow(self.screen,
+                                _("iSCSI Login Results"),
+                                msg,
+                                buttons)
+        return True if rc == TEXT_OK_CHECK else False
+
+    def get_discovery_dict(self):
+
+        dct = {
+            'username' : self._value_when(self.entry_disc_username),
+            'password' : self._value_when(self.entry_disc_password),
+            'r_username' : self._value_when(self.entry_disc_r_username),
+            'r_password' : self._value_when(self.entry_disc_r_password)
+            }
+        entered_ip = self.entry_target_ip.value()
+        (ip, port) = pih.parse_ip(entered_ip)
+        dct["ipaddr"] = ip
+        dct["port"]   = port
+        return dct
+
+    def get_initiator(self):
+        return self.entry_initiator.value()
+
+    def get_login_dict(self):
+        auth_kind = self.listbox_login.current()
+        if auth_kind == pih.CRED_REUSE[0]:
+            discovery_dict = self.get_discovery_dict()
+            dct = dict((k,discovery_dict[k]) for k in discovery_dict if k in 
+                       ['username', 
+                        'password', 
+                        'r_username', 
+                        'r_password'])
+        else:
+            dct = {
+                'username' : self._value_when(self.entry_login_username),
+                'password' : self._value_when(self.entry_login_password),
+                'r_username' : self._value_when(self.entry_login_r_username),
+                'r_password' : self._value_when(self.entry_login_r_password)
+                }
+
+        return dct
+
+    def set_initiator(self, initiator, initiator_set):
+        pass
+
+# general add drive stuff
+
 class addDriveDialog(object):
     def __init__(self, anaconda):
         self.anaconda = anaconda
@@ -151,48 +408,10 @@ class addDriveDialog(object):
                                "for iSCSI config.  Please boot with "
                                "'linux asknetwork'")
             return INSTALL_BACK
-        
-        iname = iscsi.iscsi().initiator
-        (button, entries) = EntryWindow(screen,
-                                        _("Configure iSCSI Parameters"),
-                                        _("To use iSCSI disks, you must provide the address of your iSCSI target and the iSCSI initiator name you've configured for your host."),
-                                        prompts = [ _("Target IP Address"),
-                                                    (_("iSCSI Initiator Name"),
-                                                     iname),
-                                                    _("CHAP username"),
-                                                    _("CHAP password"),
-                                                    _("Reverse CHAP username"),
-                                                    _("Reverse CHAP password") ])
-        if button == TEXT_CANCEL_CHECK:
-            return INSTALL_BACK
 
-        (user, pw, user_in, pw_in) = entries[2:]
-
-        target = entries[0].strip()
-        try:
-            count = len(target.split(":"))
-            idx = target.rfind("]:")
-            # Check for IPV6 [IPV6-ip]:port
-            if idx != -1:
-                ip = target[1:idx]
-                port = target[idx+2:]
-            # Check for IPV4 aaa.bbb.ccc.ddd:port
-            elif count == 2:
-                idx = target.rfind(":")
-                ip = target[:idx]
-                port = target[idx+1:]
-            else:
-                ip = target
-                port = "3260"
-            network.sanityCheckIPString(ip)
-        except network.IPMissing, msg:
-            raise ValueError, msg
-        except network.IPError, msg:
-            raise ValueError, msg
-
-        iname = entries[1].strip()
-        iscsi.iscsi().initiator = iname
-        iscsi.iscsi().addTarget(ip, port, user, pw, user_in, pw_in,
-                                        intf=self.anaconda.intf)
-
-        return INSTALL_OK
+        wizard = iSCSITextWizard(screen)
+        login_ok_nodes = pih.drive_iscsi_addition(self.anaconda, wizard)
+        if len(login_ok_nodes):
+            return INSTALL_OK
+        log.info("addIscsiDriveDialog(): no new nodes added")
+        return INSTALL_BACK
diff --git a/pyanaconda/textw/constants_text.py b/pyanaconda/textw/constants_text.py
index bba5ceb..b77cada 100644
--- a/pyanaconda/textw/constants_text.py
+++ b/pyanaconda/textw/constants_text.py
@@ -65,4 +65,8 @@ TEXT_EDIT_STR = N_("Edit")
 TEXT_EDIT_CHECK = "edit"
 TEXT_EDIT_BUTTON = Translator(TEXT_EDIT_STR, TEXT_EDIT_CHECK)
 
+TEXT_RETRY_STR = N_("Retry")
+TEXT_RETRY_CHECK = "retry"
+TEXT_RETRY_BUTTON = Translator(TEXT_RETRY_STR, TEXT_RETRY_CHECK)
+
 TEXT_F12_CHECK = "F12"
-- 
1.7.1.1

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list


[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux