[node-patches] Change in ovirt-node[master]: installer: Add storage vol page and more

fabiand at fedoraproject.org fabiand at fedoraproject.org
Mon Jan 28 17:34:53 UTC 2013


Fabian Deutsch has uploaded a new change for review.

Change subject: installer: Add storage vol page and more
......................................................................

installer: Add storage vol page and more

Change-Id: I5d485cb9d5740012cd666fd7a28c640af12bdfca
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M scripts/tui/src/ovirt/node/base.py
M scripts/tui/src/ovirt/node/config/defaults.py
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/password_page.py
M scripts/tui/src/ovirt/node/installer/progress_page.py
A scripts/tui/src/ovirt/node/installer/storage_vol_page.py
M scripts/tui/src/ovirt/node/ui/urwid_builder.py
M scripts/tui/src/ovirt/node/ui/widgets.py
9 files changed, 240 insertions(+), 62 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/81/11481/1

diff --git a/scripts/tui/src/ovirt/node/base.py b/scripts/tui/src/ovirt/node/base.py
index c929696..ec501b8 100644
--- a/scripts/tui/src/ovirt/node/base.py
+++ b/scripts/tui/src/ovirt/node/base.py
@@ -64,7 +64,8 @@
             for idx, cb in enumerate(self.callbacks):
                 self.logger.debug("(%d/%d) Emitting from %s: %s" %
                                   (idx + 1, len(self.callbacks), self, cb))
-                cb(target, userdata)
+                if cb(target, userdata) is False:
+                    self.logger.debug("Breaking callback sequence")
             return self
 
         def connect(self, cb):
diff --git a/scripts/tui/src/ovirt/node/config/defaults.py b/scripts/tui/src/ovirt/node/config/defaults.py
index 00a1a71..679ba95 100644
--- a/scripts/tui/src/ovirt/node/config/defaults.py
+++ b/scripts/tui/src/ovirt/node/config/defaults.py
@@ -1164,13 +1164,13 @@
         return tx
 
 
-class Storage(NodeConfigFileSection):
-    """Configure storage
-    This is a class to handle the storage parameters used at installation time
+class Installation(NodeConfigFileSection):
+    """Configure installation
+    This is a class to handle the parameters used at installation time
 
     >>> fn = "/tmp/cfg_dummy"
     >>> cfgfile = ConfigFile(fn, SimpleProvider)
-    >>> n = Storage(cfgfile)
+    >>> n = Installation(cfgfile)
     >>> kwargs = {"init": "/dev/sda", "root_install": "/dev/sdb"}
     >>> n.update(**kwargs)
     >>> data = n.retrieve().items()
@@ -1181,7 +1181,6 @@
     >>> data[6:9]
     [('logging_size', None), ('swap_size', None), ('root_size', None)]
     """
-    # FIXME this key is new!
     keys = ("OVIRT_INIT",
             "OVIRT_ROOT_INSTALL",
             "OVIRT_OVERCOMMIT",
@@ -1191,13 +1190,28 @@
             "OVIRT_VOL_LOGGING_SIZE",
             "OVIRT_VOL_CONFIG_SIZE",
             "OVIRT_VOL_DATA_SIZE",
+            "OVIRT_INSTALL"
             )
 
     @NodeConfigFileSection.map_and_update_defaults_decorator
-    def update(self, init, root_install, overcommit, root_size, efi_size,
-               swap_size, logging_size, config_size, data_size):
+    def update(self, init, root_install, overcommit, root_size,
+               efi_size, swap_size, logging_size,
+               config_size, data_size, install):
         # FIXME no checking!
-        pass
+        return {"OVIRT_INIT": ",".join(init)}
+
+    def retrieve(self):
+        cfg = dict(NodeConfigFileSection.retrieve(self))
+        cfg.update({"init": cfg["init"].split(",")})
+        return cfg
 
     def transaction(self):
         return None
+
+    def install_on(self, init):
+        """Convenience function which can be used to set the parameters which
+        are going to be picked up by the installer backend to install Node on
+        the given storage with the given othere params
+        """
+        self.update(init=init,
+                    install=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 8133aa2..748f00b 100644
--- a/scripts/tui/src/ovirt/node/installer/boot_device_page.py
+++ b/scripts/tui/src/ovirt/node/installer/boot_device_page.py
@@ -85,6 +85,7 @@
         return devices
 
     def on_change(self, changes):
+        self.logger.debug("Boot device changes: %s" % changes)
         if changes.contains_any(["boot.device"]):
             device = changes["boot.device"]
             if device == "other":
@@ -98,20 +99,21 @@
 
     def on_merge(self, effective_changes):
         changes = self.pending_changes(False)
-        if changes.contains_any(["boot.device"]):
+        if changes.contains_any(["button.back"]):
+            self.application.ui.navigate.to_previous_plugin()
+
+        elif changes.contains_any(["button.next", "boot.device"]):
+            self.application.ui.navigate.to_next_plugin()
+
+        elif changes.contains_any(["boot.device"]):
             device = changes["boot.device"]
             if device == "other":
                 self._dialog = CustomDeviceDialog("custom", "x", "y")
                 return self._dialog
 
-        if changes.contains_any(["boot.device.custom"]):
+        elif changes.contains_any(["boot.device.custom"]):
             self._dialog.close()
             self.application.ui.navigate.to_next_plugin()
-
-        if changes.contains_any(["button.next", "boot.device"]):
-            self.application.ui.navigate.to_next_plugin()
-        elif changes.contains_any(["button.back"]):
-            self.application.ui.navigate.to_previous_plugin()
 
 
 class DeviceDetails(ui.Label):
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 e7c2dd6..d2528ec 100644
--- a/scripts/tui/src/ovirt/node/installer/installation_device_page.py
+++ b/scripts/tui/src/ovirt/node/installer/installation_device_page.py
@@ -36,12 +36,11 @@
         return 40
 
     def model(self):
-        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
+            self._model["installation.device.details"] = first_dev
+            self._model["installation.device.current"] = first_dev
         return self._model
 
     def validators(self):
@@ -56,10 +55,11 @@
         ws = [ui.Header("header[0]", page_title)]
 
         if devices:
-            ws += [ui.Table("installation.device", "", " %6s  %11s  %5s" %
+            ws += [ui.Table("installation.device.current", "",
+                            " %6s  %11s  %5s" %
                             ("Location", "Device Name", "Size"), devices,
                             multi=True),
-                   DeviceDetails("label.details", "(No device)")
+                   DeviceDetails("installation.device.details", "(No device)")
                    ]
         else:
             ws += [ui.Label("installation.no_device",
@@ -83,18 +83,20 @@
                        for name, d in all_devices], key=lambda t: t[0])
 
     def on_change(self, changes):
-        if changes.contains_any(["installation.device"]):
-            highlighted_device = changes["installation.device"]
-            selected_devices = self.widgets["installation.device"].selection()
-            self.logger.debug("devices: %s" % selected_devices)
+        if changes.contains_any(["installation.device.current"]):
+            highlighted_device = changes["installation.device.current"]
+            selected_devices = self.widgets["installation.device.current"].selection()
+            self.logger.debug("selected devices: %s" % selected_devices)
+            changes["installation.devices"] = selected_devices
             self._model.update(changes)
-            w = self.widgets["label.details"]
+            w = self.widgets["installation.device.details"]
             if highlighted_device:
                 w.set_device(highlighted_device)
 
     def on_merge(self, effective_changes):
         changes = self.pending_changes(False)
-        if changes.contains_any(["installation.device", "button.next"]):
-            self.application.ui.navigate.to_next_plugin()
-        elif changes.contains_any(["button.back"]):
+        self.logger.debug("All inst changes: %s" % changes)
+        if changes.contains_any(["button.back"]):
             self.application.ui.navigate.to_previous_plugin()
+        elif changes.contains_any(["button.next"]):
+            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 3a61c22..1de11dc 100644
--- a/scripts/tui/src/ovirt/node/installer/password_page.py
+++ b/scripts/tui/src/ovirt/node/installer/password_page.py
@@ -65,7 +65,7 @@
 
     def on_merge(self, effective_changes):
         changes = self.pending_changes(False)
-        if changes.contains_any(["root.password_confirmation", "button.next"]):
-            self.application.ui.navigate.to_next_plugin()
-        elif changes.contains_any(["button.back"]):
+        if changes.contains_any(["button.back"]):
             self.application.ui.navigate.to_previous_plugin()
+        elif changes.contains_any(["root.password_confirmation", "button.next"]):
+            self.application.ui.navigate.to_next_plugin()
diff --git a/scripts/tui/src/ovirt/node/installer/progress_page.py b/scripts/tui/src/ovirt/node/installer/progress_page.py
index 76e0177..8ffe761 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
 
@@ -105,11 +106,13 @@
         tx = utils.Transaction("Installation")
 
         app = self.progress_plugin.application
-        tx.append(self.UpdateDefaultsFromModels(app))
-        tx.append(self.PartitionAndFormat())
+        model_tx = self.UpdateDefaultsFromModels(app)
+        model_tx.prepare()
+        tx.append(model_tx)
+        tx.append(self.PartitionAndFormat(model_tx.config["installation.devices"]))
         tx.append(self.SetPassword("the-password"))
-        tx.append(self.InstallBootloader())
-        tx.append(self.SetKeyboardLayout("da-layout"))
+        tx.append(self.InstallBootloader(model_tx.config["boot.device"]))
+        tx.append(self.SetKeyboardLayout(model_tx.config["keyboard.layout"]))
 
         return tx
 
@@ -130,14 +133,28 @@
                     self.logger.debug("Merged config: %s" % (model))
                 except NotImplementedError:
                     self.logger.debug("Merged no config.")
+            self.config = config
             self.logger.debug("Final config: %s" % config)
 
+            # Update/Write the config file
+            model = defaults.Installation()
+            model.update(init=[config["boot.device"]] +
+                              config["installation.devices"],
+                         install="1")
+            kbd = defaults.Keyboard()
+            kbd.update(config["keyboard.layout"])
+
         def commit(self):
-            #model = defaults.Storage()
+            #model = defaults.Installation()
             raise NotImplementedError
 
     class PartitionAndFormat(utils.Transaction.Element):
-        title = "Partitioning and Creating File Systems"
+        title_tpl = "Partitioning and Creating File Systems on '%s'"
+
+        def __init__(self, dst):
+            self.dst = dst
+            self.title = self.title_tpl % dst
+            super(InstallerThread.PartitionAndFormat, self).__init__()
 
         def commit(self):
             from ovirtnode import storage
@@ -160,7 +177,12 @@
                 raise RuntimeError("Failed to set root password")
 
     class InstallBootloader(utils.Transaction.Element):
-        title = "Installing Bootloader Configuration"
+        title_tpl = "Installing Bootloader Configuration to '%s'"
+
+        def __init__(self, dst):
+            self.dst = dst
+            self.title = self.title_tpl % dst
+            super(InstallerThread.InstallBootloader, self).__init__()
 
         def commit(self):
             from ovirtnode.install import Install
@@ -170,12 +192,12 @@
                 raise RuntimeError("Failed to set install bootloader")
 
     class SetKeyboardLayout(utils.Transaction.Element):
-        title = "Setting keyboard layout to '{kbd_layout}'"
+        title_tpl = "Setting keyboard layout to '%s'"
 
         def __init__(self, kbd_layout):
-            super(InstallerThread.SetKeyboardLayout, self).__init__()
             self.kbd_layout = kbd_layout
-            self.title = self.title.format(kbd_layout=kbd_layout)
+            self.title = self.title_tpl % kbd_layout
+            super(InstallerThread.SetKeyboardLayout, self).__init__()
 
         def commit(self):
             utils.Keyboard().set_layout(self.kbd_layout)
diff --git a/scripts/tui/src/ovirt/node/installer/storage_vol_page.py b/scripts/tui/src/ovirt/node/installer/storage_vol_page.py
new file mode 100644
index 0000000..4538908
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/installer/storage_vol_page.py
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# storage_vol_page.py - Copyright (C) 2013 Red Hat, Inc.
+# Written by Fabian Deutsch <fabiand at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# 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.
+
+"""
+Storage Volume page of the installer
+"""
+from ovirt.node import plugins, ui, utils, valid
+
+
+class Plugin(plugins.NodePlugin):
+    _model = {}
+
+    def name(self):
+        return "Storage Sizes"
+
+    def rank(self):
+        return 20
+
+    def model(self):
+        self._model = {}
+        predefined = self.__get_default_sizes()
+        # cfg = config.defaults.Storage() FIXME respect defaults entries
+        self._model.update(predefined)
+        return self._model
+
+    def validators(self):
+        is_zero = valid.Number(exactly=0)
+        min_swap, min_logging = self.__get_min_sizes()
+        return {"storage.efi_size":
+                valid.Number(bounds=[0, None]),
+                "storage.root_size":
+                valid.Number(bounds=[0, None]),
+                "storage.swap_size":
+                valid.Number(bounds=[min_swap, None]) | is_zero,
+                "storage.config_size":
+                valid.Number(bounds=[5, None]),
+                "storage.logging_size":
+                valid.Number(bounds=[min_logging, None]) | is_zero,
+                "storage.data_size":
+                valid.Number(bounds=[0, None]),
+                }
+
+    def ui_content(self):
+        ws = [ui.Header("header[0]", "Storage Volumes"),
+              ui.Label("label[0]", "Please enter the sizes for the " +
+                       "following partitions in MB"),
+              ui.Divider("divider[0]"),
+              ui.Entry("storage.efi_size", "UEFI/Bios:", enabled=False),
+              ui.Divider("divider[1]"),
+              ui.Entry("storage.root_size", "Root & RootBackup:",
+                       enabled=False),
+              ui.Label("label[1]", "(2 partitions at 256MB each)"),
+              ui.Divider("divider[2]"),
+              ui.Entry("storage.swap_size", "Swap:"),
+              ui.Entry("storage.config_size", "Config:"),
+              ui.Entry("storage.logging_size", "Logging:"),
+              ui.Entry("storage.data_size", "Data:"),
+              ]
+        self.widgets.add(ws)
+        page = ui.Page("storage", ws)
+        page.buttons = [ui.QuitButton("button.quit", "Quit"),
+                        ui.Button("button.back", "Back"),
+                        ui.SaveButton("button.next", "Next")]
+        return page
+
+    def on_change(self, changes):
+        # FIXME
+        pass
+
+    def on_merge(self, effective_changes):
+        changes = self.pending_changes(False)
+        # FIXME
+        if changes.contains_any(["button.back"]):
+            self.application.ui.navigate.to_previous_plugin()
+        elif changes.contains_any(["button.next"]):
+            self.application.ui.navigate.to_next_plugin()
+
+    def __get_min_sizes(self):
+        if self.application.args.dry:
+            return 2048, 256
+        from ovirtnode.storage import Storage
+        stor = Storage()
+        return stor.MIN_SWAP_SIZE, stor.MIN_LOGGING_SIZE
+
+    def __get_default_sizes(self):
+        if self.application.args.dry:
+            return {"storage.efi_size": "256",
+                    "storage.root_size": "50",
+                    "storage.swap_size": "0",
+                    "storage.config_size": "5",
+                    "storage.logging_size": "2048",
+                    "storage.data_size": "0",
+                    }
+        from ovirtnode.storage import Storage
+        stor = Storage()
+        sizes = {"storage.efi_size": stor.EFI_SIZE,
+                 "storage.root_size": stor.ROOT_SIZE,
+                 "storage.swap_size": stor.SWAP_SIZE,
+                 "storage.config_size": stor.CONFIG_SIZE,
+                 "storage.logging_size": stor.LOGGING_SIZE,
+                 "storage.data_size": stor.DATA_SIZE,
+                 }
+        return sizes
diff --git a/scripts/tui/src/ovirt/node/ui/urwid_builder.py b/scripts/tui/src/ovirt/node/ui/urwid_builder.py
index 5cfa89c..c5d5833 100644
--- a/scripts/tui/src/ovirt/node/ui/urwid_builder.py
+++ b/scripts/tui/src/ovirt/node/ui/urwid_builder.py
@@ -70,8 +70,7 @@
         def on_item_text_change_cb(w, v):
             self.logger.debug("Element changed, updating label " +
                               "'%s': %s" % (w, v))
-            widget.text(ui_label.text())
-            self.application.ui.force_redraw()
+            widget.text(v)
         ui_label.on_value_change.connect(on_item_text_change_cb)
 
         return widget
@@ -229,30 +228,33 @@
     def _build_table(self, ui_table):
         children = []
 
-        selected = None
         for key, label in ui_table.items:
             c = self._build_tableitem(ui_table, key, label)
             children.append(c)
-            if key == ui_table.selection():
-                selected = c
 
         widget = uw.TableWidget(ui_table.label, ui_table.header,
-                                children, selected,
+                                children, ui_table.multi,
                                 ui_table.height, ui_table.enabled())
 
+        for c in children:
+            c._table = widget
+
+        if ui_table.multi:
+            widget.selection(ui_table.selection())
+        else:
+            widget.focus(ui_table.selection())
+
         def on_change_cb(w, d=None):
-            ui_table.on_change({ui_table.path: w._key})
             if ui_table.multi:
                 ui_table.selection(widget.selection())
             else:
                 ui_table.selection(w._key)
+            ui_table.on_change({ui_table.path: w._key})
 
         urwid.connect_signal(widget, "changed", on_change_cb)
 
         def on_item_value_change_cb(p, v):
-            for c in children:
-                if c._key in v:
-                    c.selected(True)
+            widget.selection(v)
 
         ui_table.on_value_change.connect(on_item_value_change_cb)
 
@@ -263,6 +265,7 @@
         c._key = key
 
         def on_activate_cb(w, data):
+            ui_table.selection(w._table.selection())
             ui_table.on_change({ui_table.path: w._key})
             ui_table.on_activate({ui_table.path: w._key})
 
@@ -533,6 +536,7 @@
 
     def force_redraw(self):
         if self.__loop:
+            self.logger.debug("Redrawing screen")
             self.__loop.draw_screen()
 
     def size(self):
diff --git a/scripts/tui/src/ovirt/node/ui/widgets.py b/scripts/tui/src/ovirt/node/ui/widgets.py
index 447c4cc..7a95435 100644
--- a/scripts/tui/src/ovirt/node/ui/widgets.py
+++ b/scripts/tui/src/ovirt/node/ui/widgets.py
@@ -70,11 +70,14 @@
         return True
 
     def is_selected(self):
-        return self._text.text.startswith(self.checkboxes[True])
+        if self.multi:
+            return self._text.text.startswith(self.checkboxes[True])
+        return True
 
     def select(self, is_selected=True):
-        new_text = "%s%s" % (self.checkboxes[is_selected], self.title)
-        self._text.set_text(new_text)
+        if self.multi:
+            new_text = "%s%s" % (self.checkboxes[is_selected], self.title)
+            self._text.set_text(new_text)
 
     def __build_child(self):
         self._text = SelectableText(self.title)
@@ -85,6 +88,7 @@
     def __handle_activate(self):
         if self.multi:
             is_checked = self.is_selected()
+            LOGGER.debug("handling activate: %s" % is_checked)
             self.select(not is_checked)
         self._emit('activate', self)
 
@@ -106,7 +110,7 @@
 
     _position = 0
 
-    def __init__(self, label, header, items, selected_item, height, enabled):
+    def __init__(self, label, header, items, multi, height, enabled):
         self.__label = urwid.Text(label)
         self.__label_attrmap = urwid.AttrMap(self.__label, self._label_attr)
         self.__header = urwid.Text(header)
@@ -115,9 +119,7 @@
         self.__walker = urwid.SimpleListWalker(self.__items)
         self.__list = urwid.ListBox(self.__walker)
 #        self.__list_linebox = urwid.LineBox(self.__list)
-
-        if selected_item:
-            self.set_focus(items.index(selected_item))
+        self.multi = multi
 
         def __on_item_change():
             widget, self._position = self.__list.get_focus()
@@ -148,9 +150,19 @@
     def set_focus(self, n):
         self.__list.set_focus(n)
 
-    def selection(self):
-        selection = [w._key for w in self.__items if w.is_selected()]
-        return selection
+    def focus(self, key):
+        for c in self.__items:
+            if c._key == key:
+                    self.set_focus(self.__items.index(c))
+
+    def selection(self, selection=None):
+        if selection:
+            for c in self.__items:
+                LOGGER.debug("checking: %s" % c)
+                if self.multi and c._key in selection:
+                    c.select(True)
+        selected = [w._key for w in self.__items if w.is_selected()]
+        return selected
 
 
 class PluginMenuEntry(TableEntryWidget):


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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I5d485cb9d5740012cd666fd7a28c640af12bdfca
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