From e9321f9b03c32ff0b7cab676d4f66f0497c19e6c Mon Sep 17 00:00:00 2001 From: Andy Southgate Date: Wed, 30 Sep 2009 18:56:06 +0100 Subject: [PATCH] CP-1290: Display EULAs on boot if password not set --- Makefile | 1 + XSConsoleConfig.py | 4 + XSConsoleLayout.py | 2 +- XSConsoleTerm.py | 8 +- plugins-base/XSFeatureChangePassword.py | 1 + plugins-base/XSFeatureEULA.py | 100 ++++++++++++++++++++++++ plugins-base/XSFeatureShutdown.py | 9 ++- xsconsole.e4p | 7 +- 8 files changed, 122 insertions(+), 10 deletions(-) create mode 100644 plugins-base/XSFeatureEULA.py diff --git a/Makefile b/Makefile index c796510..4fe2640 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,7 @@ PLUGINS_BASE += XSFeatureDRRestore.py PLUGINS_BASE += XSFeatureDRSchedule.py PLUGINS_BASE += XSFeatureDNS.py PLUGINS_BASE += XSFeatureDisplayNICs.py +PLUGINS_BASE += XSFeatureEULA.py PLUGINS_BASE += XSFeatureHostCommon.py PLUGINS_BASE += XSFeatureHostEvacuate.py PLUGINS_BASE += XSFeatureHostInfo.py diff --git a/XSConsoleConfig.py b/XSConsoleConfig.py index 44f2088..f6e1564 100644 --- a/XSConsoleConfig.py +++ b/XSConsoleConfig.py @@ -58,6 +58,10 @@ def DisplayAssetTag(self): def BMCName(self): return 'BMC' + def FirstBootEULAs(self): + # Subclasses in XSConsoleConfigOEM can add their EULAs to this array + return ['/EULA'] + # Import a more specific configuration if available if os.path.isfile(sys.path[0]+'/XSConsoleConfigOEM.py'): import XSConsoleConfigOEM diff --git a/XSConsoleLayout.py b/XSConsoleLayout.py index e837561..6bb028b 100644 --- a/XSConsoleLayout.py +++ b/XSConsoleLayout.py @@ -78,7 +78,7 @@ def PopDialogue(self): self.dialogues.pop() if len(self.dialogues) == 1: # When the display returns to the root screen, it's possible that data has changed, so - # selete the HotData cache to force a refetch + # delete the HotData cache to force a refetch HotData.Inst().DeleteCache() self.TopDialogue().UpdateFields() self.Refresh() diff --git a/XSConsoleTerm.py b/XSConsoleTerm.py index 4511dc6..0a36a32 100644 --- a/XSConsoleTerm.py +++ b/XSConsoleTerm.py @@ -102,16 +102,18 @@ def Enter(self): Lang("The underlying Xen API xapi is not running. This console will have reduced functionality. " "Would you like to attempt to restart xapi?"), lambda x: self.HandleRestartChoice(x))) - # Request password change on first boot, or if it isn't set if not Auth.Inst().IsPasswordSet() : - XSLog("Displaying 'Please specify a password' dialogue") + # Request password change on first boot, or if it isn't set + XSLog("Displaying 'Please specify a password' dialogue and EULAs") Importer.ActivateNamedPlugIn('CHANGE_PASSWORD', Lang("Please specify a password for user 'root' before continuing")) + # Create a stack of EULA dialogues that must be accepted before the password dialogue is revealed + Importer.ActivateNamedPlugIn('EULA') elif State.Inst().PasswordChangeRequired(): Importer.ActivateNamedPlugIn('CHANGE_PASSWORD', Lang("Please change the password for user 'root' before continuing")) elif State.Inst().RebootMessage() is not None: Importer.ActivateNamedPlugIn('REBOOT', State.Inst().RebootMessage()) State.Inst().RebootMessageSet(None) - + self.layout.Clear() if not '--dryrun' in sys.argv: self.MainLoop() diff --git a/plugins-base/XSFeatureChangePassword.py b/plugins-base/XSFeatureChangePassword.py index 43e5ee6..afe8dec 100644 --- a/plugins-base/XSFeatureChangePassword.py +++ b/plugins-base/XSFeatureChangePassword.py @@ -21,6 +21,7 @@ def __init__(self, inText = None, inSuccessFunc = None): pane.TitleSet("Change Password") pane.AddBox() self.UpdateFields() + pane.InputIndexSet(None) # Reactivate cursor if this dialogue is initially covered and revealed later def UpdateFields(self): pane = self.Pane() diff --git a/plugins-base/XSFeatureEULA.py b/plugins-base/XSFeatureEULA.py new file mode 100644 index 0000000..3221c05 --- /dev/null +++ b/plugins-base/XSFeatureEULA.py @@ -0,0 +1,100 @@ +# Copyright (c) Citrix Systems 2009. All rights reserved. +# xsconsole is proprietary software. +# +# Xen, the Xen logo, XenCenter, XenMotion are trademarks or registered +# trademarks of Citrix Systems, Inc., in the United States and other +# countries. + +if __name__ == "__main__": + raise Exception("This script is a plugin for xsconsole and cannot run independently") + +from XSConsoleStandard import * + +class EULADialogue(Dialogue): + def __init__(self, inFilename): + Dialogue.__init__(self) + + xSize = Layout.Inst().APP_XSIZE + ySize = Layout.Inst().APP_YSIZE + + self.filename = inFilename + try: + file = open(inFilename) + try: + contents = ''.join(file.readlines()) + finally: + file.close() + except Exception, e: + contents = str(e) + + self.maxLine = 0 + for line in contents.split('\n'): + self.maxLine = max(self.maxLine, len(line)) + self.padding = ' ' * max(0, (xSize - 4 - self.maxLine) / 2) + + self.text = Lang("End User License Agreement") + self.info = contents + paneSizer = PaneSizerFixed(0, 1, xSize, ySize - 1) + pane = self.NewPane(DialoguePane(self.parent, paneSizer)) + pane.AddBox() + self.UpdateFields() + + def UpdateFields(self): + pane = self.Pane() + pane.ResetFields() + + pane.AddWrappedCentredBoldTextField(self.text) + + if self.info is not None: + pane.NewLine() + # Add one field per line to preserve preformatting + for line in self.info.split('\n'): + pane.AddTextField(self.padding+line) + pane.NewLine() + + helpKeys = { Lang("") : Lang("Accept") , Lang("") : Lang("Decline") } + if pane.NeedsScroll(): + helpKeys.update({ + Lang("") : Lang("Scroll") + }) + + pane.AddKeyHelpField( helpKeys ) + + def HandleKey(self, inKey): + handled = True + if inKey == 'KEY_ESCAPE': + Importer.ActivateNamedPlugIn('SHUTDOWN', Lang("You must accept the End User License Agreement to continue. Would you like to shutdown?")) + elif inKey == 'KEY_ENTER': + XSLog("User accepted EULA '"+self.filename+"'") + Layout.Inst().PopDialogue() + elif inKey == 'KEY_PPAGE': + for i in range(20): + self.Pane().ScrollPageUp() + elif inKey == 'KEY_NPAGE': + for i in range(20): + self.Pane().ScrollPageDown() + elif inKey == 'KEY_UP': + self.Pane().ScrollPageUp() + elif inKey in ('KEY_DOWN', ' '): + self.Pane().ScrollPageDown() + else: + handled = False + return handled + +class XSFeatureEULA: + @classmethod + def ActivateHandler(cls, *inParams): + for eula in Config.Inst().FirstBootEULAs(): + Layout.Inst().PushDialogue(EULADialogue(eula, *inParams)) + + def Register(self): + Importer.RegisterNamedPlugIn( + self, + 'EULA', # This key is referred to by name in XSConsoleTerm.py + { + 'activatehandler' : self.ActivateHandler + } + ) + +# Register this plugin when module is imported +XSFeatureEULA().Register() diff --git a/plugins-base/XSFeatureShutdown.py b/plugins-base/XSFeatureShutdown.py index fcdc9bf..acf63c9 100644 --- a/plugins-base/XSFeatureShutdown.py +++ b/plugins-base/XSFeatureShutdown.py @@ -40,9 +40,12 @@ def ShutdownReplyHandler(cls, inYesNo): Layout.Inst().PushDialogue(InfoDialogue(Lang("Shutdown Failed"), Lang(e))) @classmethod - def ActivateHandler(cls): - DialogueUtils.AuthenticatedOrPasswordUnsetOnly(lambda: Layout.Inst().PushDialogue(QuestionDialogue( - Lang("Do you want to shutdown this server?"), lambda x: cls.ShutdownReplyHandler(x)))) + def ActivateHandler(cls, *inParams): + if len(inParams) > 0: + banner = inParams[0] + else: + banner = Lang("Do you want to shutdown this server?") + DialogueUtils.AuthenticatedOrPasswordUnsetOnly(lambda: Layout.Inst().PushDialogue(QuestionDialogue(banner, lambda x: cls.ShutdownReplyHandler(x)))) def Register(self): Importer.RegisterNamedPlugIn( diff --git a/xsconsole.e4p b/xsconsole.e4p index 75eb9d6..786dcc7 100644 --- a/xsconsole.e4p +++ b/xsconsole.e4p @@ -1,8 +1,8 @@ - - + + Python Other @@ -86,6 +86,7 @@ XSConsoleLog.py XSConsoleMetrics.py XSConsoleRemoteTest.py + plugins-base/XSFeatureEULA.py @@ -225,4 +226,4 @@ - + \ No newline at end of file