[node-patches] Change in ovirt-node[master]: status: Add lock screen dialog and actions

fabiand at fedoraproject.org fabiand at fedoraproject.org
Tue Dec 11 20:09:43 UTC 2012


Fabian Deutsch has uploaded a new change for review.

Change subject: status: Add lock screen dialog and actions
......................................................................

status: Add lock screen dialog and actions

Change-Id: I2d3a82acf26c458d651b729cd822e52d93de9227
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M scripts/tui/src/ovirt/node/setup/status_page.py
M scripts/tui/src/ovirt/node/ui/__init__.py
M scripts/tui/src/ovirt/node/ui/tui.py
M scripts/tui/src/ovirt/node/ui/widgets.py
M scripts/tui/src/ovirt/node/utils/security.py
A scripts/tui/src/ovirt/node/utils/system.py
6 files changed, 165 insertions(+), 63 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/74/9974/1

diff --git a/scripts/tui/src/ovirt/node/setup/status_page.py b/scripts/tui/src/ovirt/node/setup/status_page.py
index f48d2fe..7a2c03a 100644
--- a/scripts/tui/src/ovirt/node/setup/status_page.py
+++ b/scripts/tui/src/ovirt/node/setup/status_page.py
@@ -18,20 +18,18 @@
 # 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.
-
-"""
-Status plugin
-"""
+import os
 import textwrap
 
-import ovirt.node.plugins
-import ovirt.node.ui
-import ovirt.node.utils as utils
-import ovirt.node.utils.virt as virt
-import ovirt.node.utils.security
+from ovirt.node import ui, plugins, utils
+from ovirt.node.utils import security, virt, system
+
+"""
+Status page plugin
+"""
 
 
-class Plugin(ovirt.node.plugins.NodePlugin):
+class Plugin(plugins.NodePlugin):
     """This is the summary page, summarizing all sorts of informations
 
     There are no validators, as there is no input.
@@ -77,45 +75,45 @@
         # Network related widgets, appearing in one row
         network_widgets = [
                 ("networking",
-                    ovirt.node.ui.KeywordLabel(aligned("Networking: "))),
+                    ui.KeywordLabel(aligned("Networking: "))),
                 ("networking.bridge",
-                    ovirt.node.ui.KeywordLabel("Bridge: ")),
+                    ui.KeywordLabel("Bridge: ")),
             ]
 
         action_widgets = [
-            ("action.lock", ovirt.node.ui.Button("Lock")),
-            ("action.logoff", ovirt.node.ui.Button("Log Off")),
-            ("action.restart", ovirt.node.ui.Button("Restart")),
-            ("action.poweroff", ovirt.node.ui.Button("Poweroff")),
+            ("action.lock", ui.Button("Lock")),
+            ("action.logoff", ui.Button("Log Off")),
+            ("action.restart", ui.Button("Restart")),
+            ("action.poweroff", ui.Button("Poweroff")),
         ]
 
         widgets = [
             ("status",
-                ovirt.node.ui.KeywordLabel(aligned("Status: "))),
-            ("status._space", ovirt.node.ui.Divider()),
+                ui.KeywordLabel(aligned("Status: "))),
+            ("status._space", ui.Divider()),
 
-            ("network._column", ovirt.node.ui.Row(network_widgets)),
-            ("network._space", ovirt.node.ui.Divider()),
+            ("network._column", ui.Row(network_widgets)),
+            ("network._space", ui.Divider()),
 
             ("logs",
-                ovirt.node.ui.KeywordLabel(aligned("Logs: "))),
-            ("logs._space", ovirt.node.ui.Divider()),
+                ui.KeywordLabel(aligned("Logs: "))),
+            ("logs._space", ui.Divider()),
 
             ("libvirt.num_guests",
-                ovirt.node.ui.KeywordLabel(aligned("Running VMs: "))),
-            ("libvirt._space", ovirt.node.ui.Divider()),
+                ui.KeywordLabel(aligned("Running VMs: "))),
+            ("libvirt._space", ui.Divider()),
 
-            ("support.hint", ovirt.node.ui.Label("Press F8 for support menu")),
-            ("support._space", ovirt.node.ui.Divider()),
+            ("support.hint", ui.Label("Press F8 for support menu")),
+            ("support._space", ui.Divider()),
 
-            ("action.hostkey", ovirt.node.ui.Button("View Host Key")),
+            ("action.hostkey", ui.Button("View Host Key")),
 
-            ("action._row", ovirt.node.ui.Row(action_widgets)),
+            ("action._row", ui.Row(action_widgets)),
         ]
         # Save it "locally" as a dict, for better accessability
         self._widgets = dict(widgets)
 
-        page = ovirt.node.ui.Page(widgets)
+        page = ui.Page(widgets)
         page.buttons = []
         return page
 
@@ -126,6 +124,13 @@
         # Handle button presses
         if "action.lock" in changes:
             self.logger.info("Locking screen")
+            self._lock_dialog = self._build_lock_dialog()
+            return self._lock_dialog
+        elif "action.unlock" in changes and "password" in changes:
+            self.logger.info("UnLocking screen")
+            pam = security.PAM()
+            if pam.authenticate(os.getlogin(), changes["password"]):
+                self._lock_dialog.close()
 
         elif "action.logoff" in changes:
             self.logger.info("Logging off")
@@ -133,9 +138,11 @@
 
         elif "action.restart" in changes:
             self.logger.info("Restarting")
+            self.dry_or(lambda: system.reboot())
 
         elif "action.poweroff" in changes:
             self.logger.info("Shutting down")
+            self.dry_or(lambda: system.poweroff())
 
         elif "action.hostkey" in changes:
             self.logger.info("Showing hostkey")
@@ -146,23 +153,37 @@
 
     def _build_dialog(self, path, txt, widgets):
         self._widgets.update(dict(widgets))
-        self._widgets[path] = ovirt.node.ui.Dialog(txt, widgets)
+        self._widgets[path] = ui.Dialog(txt, widgets)
         return self._widgets[path]
 
     def _build_hostkey_dialog(self):
-        fp, hk = ovirt.node.utils.security.get_ssh_hostkey()
+        ssh = security.Ssh()
+        fp, hk = ssh.get_hostkey()
         dialog = self._build_dialog("dialog.hostkey", "Host Key", [
             ("hostkey.fp._label",
-                ovirt.node.ui.Label("RSA Host Key Fingerprint:")),
+                ui.Label("RSA Host Key Fingerprint:")),
             ("hostkey.fp",
-                ovirt.node.ui.Label(fp)),
+                ui.Label(fp)),
 
-            ("hostkey._divider", ovirt.node.ui.Divider()),
+            ("hostkey._divider", ui.Divider()),
 
             ("hostkey._label",
-                ovirt.node.ui.Label("RSA Host Key:")),
+                ui.Label("RSA Host Key:")),
             ("hostkey",
-                ovirt.node.ui.Label("\n".join(textwrap.wrap(hk, 64)))),
+                ui.Label("\n".join(textwrap.wrap(hk, 64)))),
         ])
         dialog.buttons = []
         return dialog
+
+    def _build_lock_dialog(self):
+        widgets = [
+            ("label[0]", ui.Header("Enter the admin password to unlock")),
+            ("username", ui.KeywordLabel("Username: ", os.getlogin())),
+            ("password",
+                ui.PasswordEntry("Password:"))
+        ]
+        self._widgets = dict(widgets)
+        page = ui.Dialog("This screen is locked.", widgets)
+        page.buttons = [("action.unlock", ui.Button("Unlock"))]
+        page.escape_key = None
+        return page
diff --git a/scripts/tui/src/ovirt/node/ui/__init__.py b/scripts/tui/src/ovirt/node/ui/__init__.py
index 0bc5b86..dddc8e4 100644
--- a/scripts/tui/src/ovirt/node/ui/__init__.py
+++ b/scripts/tui/src/ovirt/node/ui/__init__.py
@@ -104,6 +104,8 @@
     """An abstract dialog, similar to a page
     """
 
+    escape_key = "esc"
+
     def __init__(self, title, children):
         super(Dialog, self).__init__(children)
         self.title = title
diff --git a/scripts/tui/src/ovirt/node/ui/tui.py b/scripts/tui/src/ovirt/node/ui/tui.py
index 21b3e69..9db25aa 100644
--- a/scripts/tui/src/ovirt/node/ui/tui.py
+++ b/scripts/tui/src/ovirt/node/ui/tui.py
@@ -90,6 +90,7 @@
                ('plugin.widget.progressbar.box', 'light gray'),
                ('plugin.widget.progressbar.uncomplete', None),
                ('plugin.widget.progressbar.complete', None, 'light gray'),
+               ('plugin.widget.options', element_styles["label"]),
                ('plugin.widget.options.label', element_styles["label"]),
                ('plugin.widget.dialog', None),
                ('plugin.widget.page', None),
@@ -125,13 +126,22 @@
         """
         assert type(dialog) is ui.Dialog
         widget = ui.builder.build_page(self, self._current_plugin, dialog)
-        return self.__display_as_dialog(widget, dialog.title)
+        return self.__display_as_dialog(widget, dialog.title,
+                                        dialog.escape_key)
+
+    def topmost_dialog(self):
+        dialog = [w for w in self.__widget_stack
+                  if type(w) is ovirt.node.ui.widgets.ModalDialog][-1:]
+        if dialog:
+            dialog = dialog[0]
+        else:
+            dialog = None
+        return dialog
 
     def close_topmost_dialog(self):
-        dialog = [w for w in self.__widget_stack
-                  if type(w) is ovirt.node.ui.widgets.ModalDialog][-1]
-        assert len(dialog) == 1
-        self.__close_dialog(dialog)
+        dialog = self.topmost_dialog()
+        if dialog:
+            self.__close_dialog(dialog)
 
     def quit(self):
         """Quit the UI
@@ -224,11 +234,11 @@
         self.logger.debug("Build and displayed plugin_page in %ss" %
                           diff)
 
-    def __display_as_dialog(self, body, title):
+    def __display_as_dialog(self, body, title, escape_key="esc"):
         self.logger.debug("Displaying dialog: %s / %s" % (body, title))
 #        filler = urwid.Filler(body, ("fixed top", 1), height=35)
         filler = urwid.Pile([body])
-        dialog = ovirt.node.ui.widgets.ModalDialog(title, filler, "esc",
+        dialog = ovirt.node.ui.widgets.ModalDialog(title, filler, escape_key,
                                                    self.__loop.widget)
         urwid.connect_signal(dialog, "close",
                              lambda: self.__close_dialog(dialog))
@@ -253,8 +263,10 @@
 
         if type(self.__loop.widget) is ovirt.node.ui.widgets.ModalDialog:
             self.logger.debug("Modal dialog escape: %s" % key)
-            if self.__loop.widget.escape_key in keys:
-                self.__close_dialog(self.__widget_stack[-1])
+            if self.__loop.widget.escape_key is None:
+                self.logger.debug("Dialog can not be closed with magic key")
+            elif self.__loop.widget.escape_key in keys:
+                self.close_topmost_dialog()
                 return
 
         if key in self._hotkeys.keys():
@@ -266,9 +278,15 @@
         return keys
 
     def __register_default_hotkeys(self):
-        self.register_hotkey(["esc"], self.quit)
+        self.register_hotkey(["esc"], self._quit_if_no_dialogs)
         self.register_hotkey(["window resize"], self._check_min_size_cb)
 
+    def _quit_if_no_dialogs(self):
+        if self.topmost_dialog() is None:
+            self.quit()
+        else:
+            self.logger.debug("There are still open dialogs")
+
     def _draw_screen(self):
         self.__loop.draw_screen()
 
diff --git a/scripts/tui/src/ovirt/node/ui/widgets.py b/scripts/tui/src/ovirt/node/ui/widgets.py
index 481c2d8..1ee45bd 100644
--- a/scripts/tui/src/ovirt/node/ui/widgets.py
+++ b/scripts/tui/src/ovirt/node/ui/widgets.py
@@ -327,12 +327,13 @@
 
     def set_notice(self, txt):
         self._notice_txt = txt
+        num_children = len(list(self._pile.contents))
         if txt:
             self._notice.set_text(txt)
-            if len(self._pile.contents) < 2:
+            if num_children < 2:
                 self._pile.contents.append((self._notice_attrmap, ("pack", 0)))
         else:
-            if len(self._pile.contents) > 1:
+            if num_children > 1:
                 self._pile.contents.pop()
 
     def get_notice(self):
@@ -389,12 +390,13 @@
     signals = ["change"]
 
     _label_attr = "plugin.widget.options.label"
+    _option_attr = "plugin.widget.options"
 
     def __init__(self, label, options, selected_option_key):
         self._options = options
         self._button_to_key = {}
         self._bgroup = []
-        self._label = urwid.Text(label + ":")
+        self._label = urwid.Text(label)
         self._label_attrmap = urwid.AttrMap(self._label, self._label_attr)
 
         self._buttons = []
@@ -404,6 +406,7 @@
             self._button_to_key[widget] = option_key
             if option_key == selected_option_key:
                 widget.set_state(True)
+            widget_attr = urwid.AttrMap(widget, self._option_attr)
             self._buttons.append(widget)
         self._columns = urwid.Columns([self._label_attrmap] + self._buttons)
         self._pile = urwid.Pile([urwid.Divider(), self._columns,
@@ -427,6 +430,7 @@
     def set_text(self, txt):
         self.select(txt)
 
+    # FIXME and disabling
 
 class Checkbox(urwid.WidgetWrap):
     signals = ['change']
diff --git a/scripts/tui/src/ovirt/node/utils/security.py b/scripts/tui/src/ovirt/node/utils/security.py
index 7d2f200..2969caf 100644
--- a/scripts/tui/src/ovirt/node/utils/security.py
+++ b/scripts/tui/src/ovirt/node/utils/security.py
@@ -21,24 +21,11 @@
 from ovirt.node import base, valid, utils
 import process
 import os.path
+import PAM as _PAM
 
 """
 Some convenience functions related to security
 """
-
-
-def get_ssh_hostkey(variant="rsa"):
-    fn_hostkey = "/etc/ssh/ssh_host_%s_key.pub" % variant
-    if not os.path.exists(fn_hostkey):
-        raise Exception("SSH hostkey does not yet exist.")
-
-    with open(fn_hostkey) as hkf:
-        hostkey = hkf.read()
-
-    hostkey_fp_cmd = "ssh-keygen -l -f '%s'" % fn_hostkey
-    stdout = process.pipe(hostkey_fp_cmd, without_retval=True)
-    fingerprint = stdout.strip().split(" ")[1]
-    return (fingerprint, hostkey)
 
 
 class Passwd(base.Base):
@@ -118,3 +105,40 @@
             ofunc.ovirt_store_config("/etc/ssh/sshd_config")
             self.restart()
         return aug.get(augpath)
+
+    def get_hostkey(self, variant="rsa"):
+        fn_hostkey = "/etc/ssh/ssh_host_%s_key.pub" % variant
+        if not os.path.exists(fn_hostkey):
+            raise Exception("SSH hostkey does not yet exist.")
+
+        with open(fn_hostkey) as hkf:
+            hostkey = hkf.read()
+
+        hostkey_fp_cmd = "ssh-keygen -l -f '%s'" % fn_hostkey
+        stdout = process.pipe(hostkey_fp_cmd, without_retval=True)
+        fingerprint = stdout.strip().split(" ")[1]
+        return (fingerprint, hostkey)
+
+
+class PAM(base.Base):
+    def _pam_conv(self, auth, query_list):
+        resp = []
+        for i in range(len(query_list)):
+            resp.append((self._password, 0))
+        return resp
+
+    def authenticate(self, username, password):
+        is_authenticated = False
+        auth = _PAM.pam()
+        auth.start("passwd")
+        auth.set_item(_PAM.PAM_USER, username)
+        self._password = password
+        auth.set_item(_PAM.PAM_CONV, lambda a, q: self._pam_conv(a, q))
+        try:
+            auth.authenticate()
+            is_authenticated = True
+        except _PAM.error, (resp, code):
+            self.logger.debug("Failed to authenticate: %s %s" % (resp, code))
+        except Exception as e:
+            self.logger.debug("Internal error: %s" % e)
+        return is_authenticated
diff --git a/scripts/tui/src/ovirt/node/utils/system.py b/scripts/tui/src/ovirt/node/utils/system.py
new file mode 100644
index 0000000..6702896
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/utils/system.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# system.py - Copyright (C) 2012 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.
+
+"""
+A module to access system wide stuff 
+e.g. services, reboot ...
+"""
+
+from ovirt.node.utils import process
+
+def reboot():
+    process.system("reboot")
+
+def poweroff():
+    process.system("poweroff")
\ No newline at end of file


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

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