[node-patches] Change in ovirt-node[master]: [DRAFT] ui: Installer

fabiand at fedoraproject.org fabiand at fedoraproject.org
Tue Jan 15 20:05:41 UTC 2013


Fabian Deutsch has uploaded a new change for review.

Change subject: [DRAFT] ui: Installer
......................................................................

[DRAFT] ui: Installer

Change-Id: I0c81e0e85ff35ee073dd5e47df9f53da0a8f7738
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M scripts/tui/src/ovirt/node/installer/boot_device_page.py
M scripts/tui/src/ovirt/node/installer/installation_device_page.py
M scripts/tui/src/ovirt/node/installer/keyboard_page.py
M scripts/tui/src/ovirt/node/installer/password_page.py
M scripts/tui/src/ovirt/node/installer/progress_page.py
M scripts/tui/src/ovirt/node/installer/welcome_page.py
6 files changed, 209 insertions(+), 88 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/66/11066/1

diff --git a/scripts/tui/src/ovirt/node/installer/boot_device_page.py b/scripts/tui/src/ovirt/node/installer/boot_device_page.py
index 3c83212..64a951c 100644
--- a/scripts/tui/src/ovirt/node/installer/boot_device_page.py
+++ b/scripts/tui/src/ovirt/node/installer/boot_device_page.py
@@ -22,12 +22,11 @@
 """
 Boot device selection page of the installer
 """
-from ovirt.node import plugins, ui, utils
+from ovirt.node import plugins, ui, utils, valid
 
 
 class Plugin(plugins.NodePlugin):
-    _model = None
-    _elements = None
+    _model = {}
 
     def name(self):
         return "Boot Device"
@@ -36,58 +35,85 @@
         return 30
 
     def model(self):
-        return self._model or {}
+        self._model.update({"boot.device": ""})
+        devices = self._device_list()
+        if devices:
+            first_dev = devices[0][0]
+            self._model["label.details"] = first_dev
+            self._model["boot.device"] = first_dev
+        return self._model
 
     def validators(self):
-        return {}
+        return {"boot.device": lambda v: None if v else "No device given"
+                }
 
     def ui_content(self):
         page_title = "Please select the disk to use for booting %s" % \
                      self.application.product.PRODUCT_SHORT
 
-        ws = [ui.Header("header[0]", page_title),
-              ui.Table("boot.device", "", " %6s  %11s  %5s" %
-                       ("Location", "Device Name", "Size"),
-                       self._device_list()),
-              DeviceDetails("label.details", "(No device)")
-              ]
+        devices = self._device_list()
+
+        ws = [ui.Header("header[0]", page_title)]
+        
+        if devices:
+            ws += [ui.Table("boot.device", "", " %6s  %11s  %5s" %
+                            ("Location", "Device Name", "Size"), devices),
+                   DeviceDetails("label.details", "(No device)")
+                   ]
+        else:
+            ws += [ui.Label("boot.no_device",
+                            "No Valid Boot Devices Detected")]
 
         self.widgets.add(ws)
         page = ui.Page("boot", ws)
-        page.buttons = [ui.Button("button.quit", "Quit"),
+        page.buttons = [ui.QuitButton("button.quit", "Quit"),
                         ui.Button("button.back", "Back"),
-                        ui.Button("button.next", "Continue")]
+                        ui.SaveButton("button.next", "Continue")]
         return page
 
     def _device_list(self):
-        devices = utils.storage.Devices(fake=True)
+        do_fake = False
+        if self.application.args.dry:
+            do_fake = True
+        devices = utils.storage.Devices(fake=do_fake)
         all_devices = devices.get_all().items()
-        return [(name, " %6s  %11s  %5s GB" % (d.bus, d.name, d.size))
-                for name, d in all_devices]
+        return sorted([(name, " %6s  %11s  %5s GB" % (d.bus, d.name, d.size))
+                       for name, d in all_devices], key=lambda t: t[0])
 
     def on_change(self, changes):
-        if "button.next" in changes:
-            self._elements["label.details"].set_device(changes["button.next"])
+        if changes.contains_any(["boot.device"]):
+            self._model.update(changes)
+            self.widgets["label.details"].set_device(changes["boot.device"])
 
     def on_merge(self, effective_changes):
         changes = self.pending_changes(False)
         if changes.contains_any(["button.next", "boot.device"]):
-            self.transaction = "a"
             self.application.ui.navigate.to_next_plugin()
+        elif changes.contains_any(["button.back"]):
+            self.application.ui.navigate.to_previous_plugin()
 
 
 class DeviceDetails(ui.Label):
-    def set_device(self, device):
+    def set_device(self, device_name):
         devices = utils.storage.Devices(fake=True)
         all_devices = devices.get_all()
-        if not all_devices:
-            pass
-        """lines = [("Disk Details",),
-                 ("Device", ""),
-                 ("Model", ""),
-                 ("Bus Type", ""),
-                 ("Serial", ""),
-                 ("Size", ""),
-                 ("Description", ""),
-                 ]"""
-        self.set_text("%s" % device)
+        device = all_devices[device_name]
+
+        lines = [("Device", device.name),
+                 ("Model", device.model),
+                 ("Bus Type", device.bus),
+                 ("Serial", device.serial),
+                 ("Size (GB)", device.size),
+                 ("Description", device.desc),
+                 ]
+
+        width = max([len(o[0]) for o in lines])
+        txt = "Disk Details\n"
+        txt += "\n".join(["%s: %s" % (("{:%d}" % width).format(a), b)
+                          for a, b in lines])
+        self.text(txt)
+
+    def value(self, value=None):
+        if value:
+            self.set_device(value)
+        return value
diff --git a/scripts/tui/src/ovirt/node/installer/installation_device_page.py b/scripts/tui/src/ovirt/node/installer/installation_device_page.py
index edd3fec..a0e586c 100644
--- a/scripts/tui/src/ovirt/node/installer/installation_device_page.py
+++ b/scripts/tui/src/ovirt/node/installer/installation_device_page.py
@@ -27,8 +27,7 @@
 
 
 class Plugin(plugins.NodePlugin):
-    _model = None
-    _elements = None
+    _model = {}
 
     def name(self):
         return "Data Device"
@@ -37,7 +36,13 @@
         return 40
 
     def model(self):
-        return self._model or {}
+        self._model.update({"installation.device": ""})
+        devices = self._device_list()
+        if devices:
+            first_dev = devices[0][0]
+            self._model["label.details"] = first_dev
+            self._model["installation.device"] = first_dev
+        return self._model
 
     def validators(self):
         return {}
@@ -46,32 +51,45 @@
         page_title = "Please select the disk(s) to use for installation " \
                      "of %s" % self.application.product.PRODUCT_SHORT
 
-        ws = [ui.Header("header[0]", page_title),
-              ui.Table("installation.device", "", " %6s  %11s  %5s" %
-                       ("Location", "Device Name", "Size"),
-                       self._device_list()),
-              DeviceDetails("label.details", "(No device)")
-              ]
+        devices = self._device_list()
 
-        self.widgets.add(ws)
+        ws = [ui.Header("header[0]", page_title)]
+        
+        if devices:
+            ws += [ui.Table("installation.device", "", " %6s  %11s  %5s" %
+                            ("Location", "Device Name", "Size"), devices),
+                   DeviceDetails("label.details", "(No device)")
+                   ]
+        else:
+            ws += [ui.Label("installation.no_device",
+                            "No Valid Install Devices Detected")]
+
         page = ui.Page("device", ws)
-        page.buttons = [ui.Button("button.quit", "Quit"),
+        page.buttons = [ui.QuitButton("button.quit", "Quit"),
                         ui.Button("button.back", "Back"),
-                        ui.Button("button.next", "Continue")]
+                        ui.SaveButton("button.next", "Continue")]
+
+        self.widgets.add(page)
         return page
 
     def _device_list(self):
-        devices = utils.storage.Devices(fake=True)
+        do_fake = False
+        if self.application.args.dry:
+            do_fake = True
+        devices = utils.storage.Devices(fake=do_fake)
         all_devices = devices.get_all().items()
-        return [(name, " %6s  %11s  %5s GB" % (d.bus, d.name, d.size))
-                for name, d in all_devices]
+        return sorted([(name, " %6s  %11s  %5s GB" % (d.bus, d.name, d.size))
+                       for name, d in all_devices], key=lambda t: t[0])
 
     def on_change(self, changes):
-        if "button.next" in changes:
-            self._elements["label.details"].set_device(changes["button.next"])
+        if changes.contains_any(["installation.device"]):
+            self._model.update(changes)
+            w = self.widgets["label.details"]
+            w.set_device(changes["installation.device"])
 
     def on_merge(self, effective_changes):
         changes = self.pending_changes(False)
         if changes.contains_any(["installation.device", "button.next"]):
-            self.transaction = "a"
             self.application.ui.navigate.to_next_plugin()
+        elif changes.contains_any(["button.back"]):
+            self.application.ui.navigate.to_previous_plugin()
diff --git a/scripts/tui/src/ovirt/node/installer/keyboard_page.py b/scripts/tui/src/ovirt/node/installer/keyboard_page.py
index 557c823..6bf9697 100644
--- a/scripts/tui/src/ovirt/node/installer/keyboard_page.py
+++ b/scripts/tui/src/ovirt/node/installer/keyboard_page.py
@@ -27,7 +27,6 @@
 
 class Plugin(plugins.NodePlugin):
     _model = {}
-    _elements = None
 
     def name(self):
         return "Keyboard"
@@ -36,21 +35,24 @@
         return 20
 
     def model(self):
-        return self._model or {}
+        return self._model
 
     def validators(self):
         return {}
 
     def ui_content(self):
         kbd = utils.Keyboard()
+        c = kbd.get_current()
+        self.logger.debug("Current layout: %s" % c)
         ws = [ui.Header("header[0]", "Keyboard Layout Selection"),
               ui.Table("keyboard.layout", "Available Keyboard Layouts",
-                       "", kbd.available_layouts()),
+                       "", kbd.available_layouts(), c),
+              ui.Label("label[0]", "(Hit return to select a layout)")
               ]
         self.widgets.add(ws)
         page = ui.Page("keyboard", ws)
-        page.buttons = [ui.Button("button.quit", "Quit"),
-                        ui.Button("button.next", "Continue")]
+        page.buttons = [ui.QuitButton("button.quit", "Quit"),
+                        ui.SaveButton("button.next", "Continue")]
         return page
 
     def on_change(self, changes):
@@ -60,5 +62,8 @@
     def on_merge(self, effective_changes):
         changes = self.pending_changes(False)
         if changes.contains_any(["keyboard.layout", "button.next"]):
-            self.transaction = "a"
+            # Apply kbd layout directly so it takes affect on the password page
+            kbd = utils.Keyboard()
+            self.dry_or(lambda: kbd.set_layout(changes["keyboard.layout"]))
+
             self.application.ui.navigate.to_next_plugin()
diff --git a/scripts/tui/src/ovirt/node/installer/password_page.py b/scripts/tui/src/ovirt/node/installer/password_page.py
index 30327a2..4c0edad 100644
--- a/scripts/tui/src/ovirt/node/installer/password_page.py
+++ b/scripts/tui/src/ovirt/node/installer/password_page.py
@@ -18,16 +18,16 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.  A copy of the GNU General Public License is
 # also available at http://www.gnu.org/copyleft/gpl.html.
+from ovirt.node import plugins, ui, valid
+from ovirt.node.plugins import Validator
 
 """
 Password page of the installer
 """
-from ovirt.node import plugins, ui
 
 
 class Plugin(plugins.NodePlugin):
-    _model = None
-    _elements = None
+    _model = {}
 
     def name(self):
         return "Console Password"
@@ -39,7 +39,10 @@
         return self._model or {}
 
     def validators(self):
-        return {}
+        return {"root.password_confirmation":
+                Validator.SameAsIn(self, "root.password", "Password") | \
+                valid.Empty()
+                }
 
     def ui_content(self):
         ws = [ui.Header("header[0]",
@@ -51,16 +54,18 @@
               ]
         self.widgets.add(ws)
         page = ui.Page("password", ws)
-        page.buttons = [ui.Button("button.quit", "Quit"),
+        page.buttons = [ui.QuitButton("button.quit", "Quit"),
                         ui.Button("button.back", "Back"),
-                        ui.Button("button.next", "Install")]
+                        ui.SaveButton("button.next", "Install")]
         return page
 
     def on_change(self, changes):
-        pass
+        if changes.contains_any(["root.password_confirmation"]):
+            self._model.update(changes)
 
     def on_merge(self, effective_changes):
         changes = self.pending_changes(False)
         if changes.contains_any(["root.password_confirmation", "button.next"]):
-            self.transaction = "a"
             self.application.ui.navigate.to_next_plugin()
+        elif changes.contains_any(["button.back"]):
+            self.application.ui.navigate.to_previous_plugin()
diff --git a/scripts/tui/src/ovirt/node/installer/progress_page.py b/scripts/tui/src/ovirt/node/installer/progress_page.py
index c2dfab7..134ce2f 100644
--- a/scripts/tui/src/ovirt/node/installer/progress_page.py
+++ b/scripts/tui/src/ovirt/node/installer/progress_page.py
@@ -19,6 +19,7 @@
 # MA  02110-1301, USA.  A copy of the GNU General Public License is
 # also available at http://www.gnu.org/copyleft/gpl.html.
 from ovirt.node import plugins, ui, utils
+from ovirt.node.config import defaults
 import threading
 import time
 
@@ -29,8 +30,6 @@
 
 
 class Plugin(plugins.NodePlugin):
-    _model = None
-    _elements = None
     _worker = None
 
     def __init__(self, application):
@@ -44,7 +43,7 @@
         return 60
 
     def model(self):
-        return self._model or {}
+        return {}
 
     def validators(self):
         return {}
@@ -83,8 +82,8 @@
         time.sleep(0.3)  # Give the UI some time to build
         transaction = self.__build_transaction()
 
-        progressbar = self.progress_plugin._elements["progressbar"]
-        log = self.progress_plugin._elements["log"]
+        progressbar = self.progress_plugin.widgets["progressbar"]
+        log = self.progress_plugin.widgets["log"]
         log_lines = []
 
         txlen = len(transaction)
@@ -104,27 +103,39 @@
             log.text("EXECPTION: %s" % e)
 
     def __build_transaction(self):
-        self.__update_defaults_from_models()
-
         tx = utils.Transaction("Installation")
 
+        app = self.progress_plugin.application
+        tx.append(self.UpdateDefaultsFromModels(app))
         tx.append(self.PartitionAndFormat())
         tx.append(self.SetPassword("the-password"))
         tx.append(self.InstallBootloader())
+        tx.append(self.SetKeyboardLayout("da-layout"))
 
         return tx
 
-    def __update_defaults_from_models(self):
-        config = {}
-        app = self.progress_plugin.application
-        for pname, plugin in app.plugins().items():
-            self.logger.debug("Config for %s" % (pname))
-            try:
-                model = plugin.model()
-                config.update(model)
-                self.logger.debug("Merged config: %s" % (model))
-            except NotImplementedError:
-                self.logger.debug("Merged no config.")
+    class UpdateDefaultsFromModels(utils.Transaction.Element):
+        title = "Write configuration file"
+
+        def __init__(self, application):
+            super(InstallerThread.UpdateDefaultsFromModels, self).__init__()
+            self.application = application
+
+        def prepare(self):
+            config = {}
+            for pname, plugin in self.application.plugins().items():
+                self.logger.debug("Config for page %s" % (pname))
+                try:
+                    model = plugin.model()
+                    config.update(model)
+                    self.logger.debug("Merged config: %s" % (model))
+                except NotImplementedError:
+                    self.logger.debug("Merged no config.")
+            self.logger.debug("Final config: %s" % config)
+
+        def commit(self):
+            model = defaults.Storage()
+            raise NotImplementedError
 
     class PartitionAndFormat(utils.Transaction.Element):
         title = "Partitioning and Creating File Systems"
@@ -158,3 +169,14 @@
             boot_setup = install.ovirt_boot_setup()
             if not boot_setup:
                 raise RuntimeError("Failed to set install bootloader")
+
+    class SetKeyboardLayout(utils.Transaction.Element):
+        title = "Setting keyboard layout to '{kbd_layout}'"
+
+        def __init__(self, kbd_layout):
+            super(InstallerThread.SetKeyboardLayout, self).__init__()
+            self.kbd_layout = kbd_layout
+            self.title = self.title.format(kbd_layout=kbd_layout)
+
+        def commit(self):
+            utils.Keyboard().set_layout(self.kbd_layout)
diff --git a/scripts/tui/src/ovirt/node/installer/welcome_page.py b/scripts/tui/src/ovirt/node/installer/welcome_page.py
index 26aaffa..7533402 100644
--- a/scripts/tui/src/ovirt/node/installer/welcome_page.py
+++ b/scripts/tui/src/ovirt/node/installer/welcome_page.py
@@ -18,6 +18,9 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.  A copy of the GNU General Public License is
 # also available at http://www.gnu.org/copyleft/gpl.html.
+from ovirt.node import plugins, ui, utils
+from ovirt.node.utils import virt, system
+import os
 
 """
 Welcome page of the installer
@@ -29,14 +32,12 @@
 NOTE: Each page stores the information in the config page
 NOTE II: Or shall we build the transactions per page?
 """
-from ovirt.node import plugins, ui
 
 
 class Plugin(plugins.NodePlugin):
     """The welcome page plugin
     """
     _model = {}
-    _elements = None
 
     def name(self):
         return "Welcome"
@@ -51,12 +52,13 @@
         return {}
 
     def ui_content(self):
-        ws = [ui.Button("button.install", "Install %s" %
-                        str(self.application.product)),
-              ]
+        ws = [ui.Header("header[0]", "Installation")]
+        ws += [self.___installation_option()]
+        ws += [ui.Divider("divider[0]")]
+        ws += self.__additional_infos()
         self.widgets.add(ws)
         page = ui.Page("welcome", ws)
-        page.buttons = [ui.Button("button.quit", "Quit")]
+        page.buttons = [ui.QuitButton("button.quit", "Quit")]
         return page
 
     def on_change(self, changes):
@@ -64,5 +66,48 @@
 
     def on_merge(self, effective_changes):
         if "button.install" in effective_changes:
-            self.transaction = "a"
             self.application.ui.navigate.to_next_plugin()
+
+    def ___installation_option(self):
+        if self.application.args.dry:
+            return ui.Button("button.install", "Install Hypervisor (dry)")
+
+        media = utils.system.InstallationMedia()
+        installed = utils.system.InstalledMedia()
+
+        has_hostvg = os.path.exists("/dev/HostVG")
+        has_root = os.path.exists("/dev/disk/by-label/ROOT")
+
+        if has_hostvg and has_root:
+            return ui.Label("Major version upgrades are unsupported, " +
+                            "uninstall existing version first")
+
+        if has_hostvg:
+            try:
+                if media > installed:
+                    return ui.Button("button.upgrade",
+                                     "Upgrade %s to %s" % (media, installed))
+                elif media < installed:
+                    return ui.Button("button.downgrade",
+                                     "Downgrade %s to %s" % (media,
+                                                             installed))
+                return ui.Button("button.reinstall",
+                                 "Reinstall %s" % installed)
+            except:
+                self.logger.error("Unable to get version numbers for " +
+                                  "upgrade, invalid installation or media")
+                return ui.Label("Invalid installation, please reboot from " +
+                                "media and choose Reinstall")
+
+        return ui.Button("button.install", "Install Hypervisor %s" % media)
+
+    def __additional_infos(self):
+        ws = []
+        ws.append(ui.Label("welcome.virt", "Info: %s" %
+                           virt.hardware_status()))
+        if system.is_efi():
+            ws.append(ui.Label("welcome.efi",
+                               "Info: Machine is booted in EFI mode"))
+        if self.application.args.dry:
+            ws.append(ui.Label("dry", "Info: DRY MODE"))
+        return ws


--
To view, visit http://gerrit.ovirt.org/11066
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0c81e0e85ff35ee073dd5e47df9f53da0a8f7738
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-node
Gerrit-Branch: master
Gerrit-Owner: Fabian Deutsch <fabiand at fedoraproject.org>



More information about the node-patches mailing list