[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