diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/ValidationKit/testmanager/cgi | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/VBox/ValidationKit/testmanager/cgi/Makefile.kmk | 46 | ||||
-rwxr-xr-x | src/VBox/ValidationKit/testmanager/cgi/admin.py | 77 | ||||
-rwxr-xr-x | src/VBox/ValidationKit/testmanager/cgi/debuginfo.py | 71 | ||||
-rwxr-xr-x | src/VBox/ValidationKit/testmanager/cgi/index.py | 78 | ||||
-rwxr-xr-x | src/VBox/ValidationKit/testmanager/cgi/logout.py | 79 | ||||
-rwxr-xr-x | src/VBox/ValidationKit/testmanager/cgi/logout2.py | 81 | ||||
-rwxr-xr-x | src/VBox/ValidationKit/testmanager/cgi/rest.py | 81 | ||||
-rwxr-xr-x | src/VBox/ValidationKit/testmanager/cgi/status.py | 519 | ||||
-rwxr-xr-x | src/VBox/ValidationKit/testmanager/cgi/testboxdisp.py | 75 |
9 files changed, 1107 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/testmanager/cgi/Makefile.kmk b/src/VBox/ValidationKit/testmanager/cgi/Makefile.kmk new file mode 100644 index 00000000..74d882cc --- /dev/null +++ b/src/VBox/ValidationKit/testmanager/cgi/Makefile.kmk @@ -0,0 +1,46 @@ +# $Id: Makefile.kmk $ +## @file +# VirtualBox Validation Kit. +# + +# +# Copyright (C) 2006-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# 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, in version 3 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, see <https://www.gnu.org/licenses>. +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +# in the VirtualBox distribution, in which case the provisions of the +# CDDL are applicable instead of those of the GPL. +# +# You may elect to license modified versions of this file under the +# terms and conditions of either the GPL or the CDDL or both. +# +# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + + +VBOX_VALIDATIONKIT_PYTHON_SOURCES += $(wildcard $(PATH_SUB_CURRENT)/*.py) + +$(evalcall def_vbox_validationkit_process_python_sources) +$(evalcall def_vbox_validationkit_process_js_sources) +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/ValidationKit/testmanager/cgi/admin.py b/src/VBox/ValidationKit/testmanager/cgi/admin.py new file mode 100755 index 00000000..b8c10f76 --- /dev/null +++ b/src/VBox/ValidationKit/testmanager/cgi/admin.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# $Id: admin.py $ + +""" +CGI - Administrator Web-UI. +""" + +__copyright__ = \ +""" +Copyright (C) 2012-2023 Oracle and/or its affiliates. + +This file is part of VirtualBox base platform packages, as +available from https://www.virtualbox.org. + +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, in version 3 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, see <https://www.gnu.org/licenses>. + +The contents of this file may alternatively be used under the terms +of the Common Development and Distribution License Version 1.0 +(CDDL), a copy of it is provided in the "COPYING.CDDL" file included +in the VirtualBox distribution, in which case the provisions of the +CDDL are applicable instead of those of the GPL. + +You may elect to license modified versions of this file under the +terms and conditions of either the GPL or the CDDL or both. + +SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +""" +__version__ = "$Revision: 155244 $" + + +# Standard python imports. +import os +import sys + +# Only the main script needs to modify the path. +g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))); +sys.path.append(g_ksValidationKitDir); + +# Validation Kit imports. +from testmanager import config; +from testmanager.core.webservergluecgi import WebServerGlueCgi; +from testmanager.webui.wuiadmin import WuiAdmin; + +def main(): + """ + Main function a la C/C++. Returns exit code. + """ + + oSrvGlue = WebServerGlueCgi(g_ksValidationKitDir, fHtmlOutput = True); + try: + oWui = WuiAdmin(oSrvGlue); + oWui.dispatchRequest(); + oSrvGlue.flush(); + except Exception as oXcpt: + return oSrvGlue.errorPage('Internal error: %s' % (str(oXcpt),), sys.exc_info()); + + return 0; + +if __name__ == '__main__': + if config.g_kfProfileAdmin: + from testmanager.debug import cgiprofiling; + sys.exit(cgiprofiling.profileIt(main)); + else: + sys.exit(main()); + diff --git a/src/VBox/ValidationKit/testmanager/cgi/debuginfo.py b/src/VBox/ValidationKit/testmanager/cgi/debuginfo.py new file mode 100755 index 00000000..a2663436 --- /dev/null +++ b/src/VBox/ValidationKit/testmanager/cgi/debuginfo.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# $Id: debuginfo.py $ + +""" +CGI - Debug Info Page. +""" + +__copyright__ = \ +""" +Copyright (C) 2012-2023 Oracle and/or its affiliates. + +This file is part of VirtualBox base platform packages, as +available from https://www.virtualbox.org. + +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, in version 3 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, see <https://www.gnu.org/licenses>. + +The contents of this file may alternatively be used under the terms +of the Common Development and Distribution License Version 1.0 +(CDDL), a copy of it is provided in the "COPYING.CDDL" file included +in the VirtualBox distribution, in which case the provisions of the +CDDL are applicable instead of those of the GPL. + +You may elect to license modified versions of this file under the +terms and conditions of either the GPL or the CDDL or both. + +SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +""" +__version__ = "$Revision: 155244 $" + + +# Standard python imports. +import os +import sys + +# Only the main script needs to modify the path. +g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))); +sys.path.append(g_ksValidationKitDir); + +# Validation Kit imports. +from testmanager.core.webservergluecgi import WebServerGlueCgi; + + +def main(): + """ + Main function a la C/C++. Returns exit code. + """ + + oSrvGlue = WebServerGlueCgi(g_ksValidationKitDir, fHtmlOutput = True); + try: + oSrvGlue.debugInfoPage(); + oSrvGlue.flush(); + except Exception as oXcpt: + return oSrvGlue.errorPage('Internal error: %s' % (str(oXcpt),), sys.exc_info()); + + return 0; + +if __name__ == '__main__': + sys.exit(main()); + diff --git a/src/VBox/ValidationKit/testmanager/cgi/index.py b/src/VBox/ValidationKit/testmanager/cgi/index.py new file mode 100755 index 00000000..b9b546c2 --- /dev/null +++ b/src/VBox/ValidationKit/testmanager/cgi/index.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# $Id: index.py $ + +""" +CGI - Web UI - Main (index) page. +""" + +__copyright__ = \ +""" +Copyright (C) 2012-2023 Oracle and/or its affiliates. + +This file is part of VirtualBox base platform packages, as +available from https://www.virtualbox.org. + +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, in version 3 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, see <https://www.gnu.org/licenses>. + +The contents of this file may alternatively be used under the terms +of the Common Development and Distribution License Version 1.0 +(CDDL), a copy of it is provided in the "COPYING.CDDL" file included +in the VirtualBox distribution, in which case the provisions of the +CDDL are applicable instead of those of the GPL. + +You may elect to license modified versions of this file under the +terms and conditions of either the GPL or the CDDL or both. + +SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +""" +__version__ = "$Revision: 155244 $" + + +# Standard python imports. +import os +import sys + +# Only the main script needs to modify the path. +g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))); +sys.path.append(g_ksValidationKitDir); + +# Validation Kit imports. +from testmanager import config; +from testmanager.core.webservergluecgi import WebServerGlueCgi; +from testmanager.webui.wuimain import WuiMain; + + +def main(): + """ + Main function a la C/C++. Returns exit code. + """ + + oSrvGlue = WebServerGlueCgi(g_ksValidationKitDir, fHtmlOutput = False); + try: + oWui = WuiMain(oSrvGlue); + oWui.dispatchRequest(); + oSrvGlue.flush(); + except Exception as oXcpt: + return oSrvGlue.errorPage('Internal error: %s' % (str(oXcpt),), sys.exc_info()); + + return 0; + +if __name__ == '__main__': + if config.g_kfProfileIndex: + from testmanager.debug import cgiprofiling; + sys.exit(cgiprofiling.profileIt(main)); + else: + sys.exit(main()); + diff --git a/src/VBox/ValidationKit/testmanager/cgi/logout.py b/src/VBox/ValidationKit/testmanager/cgi/logout.py new file mode 100755 index 00000000..109bfa86 --- /dev/null +++ b/src/VBox/ValidationKit/testmanager/cgi/logout.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# $Id: logout.py $ + +""" +VirtualBox Validation Kit - CGI - Log out page. +""" + +__copyright__ = \ +""" +Copyright (C) 2012-2023 Oracle and/or its affiliates. + +This file is part of VirtualBox base platform packages, as +available from https://www.virtualbox.org. + +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, in version 3 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, see <https://www.gnu.org/licenses>. + +The contents of this file may alternatively be used under the terms +of the Common Development and Distribution License Version 1.0 +(CDDL), a copy of it is provided in the "COPYING.CDDL" file included +in the VirtualBox distribution, in which case the provisions of the +CDDL are applicable instead of those of the GPL. + +You may elect to license modified versions of this file under the +terms and conditions of either the GPL or the CDDL or both. + +SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +""" +__version__ = "$Revision: 155244 $" + + +# Standard python imports. +import os +import sys + +# Only the main script needs to modify the path. +g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))); +sys.path.append(g_ksValidationKitDir); + +# Validation Kit imports. +from testmanager.core.webservergluecgi import WebServerGlueCgi + + +def main(): + """ + Main function a la C/C++. Returns exit code. + """ + + oSrvGlue = WebServerGlueCgi(g_ksValidationKitDir, fHtmlOutput = True) + sUser = oSrvGlue.getLoginName() + if sUser not in (oSrvGlue.ksUnknownUser, 'logout'): + oSrvGlue.write('<p>Broken apache config!\n' + 'The logout.py script should be configured with .htaccess-logout and require user logout!</p>') + else: + oSrvGlue.write('<p>Successfully logged out!</p>') + oSrvGlue.write('<p><a href="%sadmin.py">Log in</a> under another user name.</p>' % + (oSrvGlue.getBaseUrl(),)) + + + oSrvGlue.write('<hr/><p>debug info:</p>') + oSrvGlue.debugInfoPage() + oSrvGlue.flush() + + return 0 + +if __name__ == '__main__': + sys.exit(main()) + diff --git a/src/VBox/ValidationKit/testmanager/cgi/logout2.py b/src/VBox/ValidationKit/testmanager/cgi/logout2.py new file mode 100755 index 00000000..1ab24cbc --- /dev/null +++ b/src/VBox/ValidationKit/testmanager/cgi/logout2.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# $Id: logout2.py $ + +""" +VirtualBox Validation Kit - CGI - Log out page for Safari. +""" + +__copyright__ = \ +""" +Copyright (C) 2012-2023 Oracle and/or its affiliates. + +This file is part of VirtualBox base platform packages, as +available from https://www.virtualbox.org. + +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, in version 3 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, see <https://www.gnu.org/licenses>. + +The contents of this file may alternatively be used under the terms +of the Common Development and Distribution License Version 1.0 +(CDDL), a copy of it is provided in the "COPYING.CDDL" file included +in the VirtualBox distribution, in which case the provisions of the +CDDL are applicable instead of those of the GPL. + +You may elect to license modified versions of this file under the +terms and conditions of either the GPL or the CDDL or both. + +SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +""" +__version__ = "$Revision: 155244 $" + + +# Standard python imports. +import os +import sys + +# Only the main script needs to modify the path. +g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))); +sys.path.append(g_ksValidationKitDir); + +# Validation Kit imports. +from testmanager.core.webservergluecgi import WebServerGlueCgi; + + +def main(): + """ + Main function a la C/C++. Returns exit code. + """ + + oSrvGlue = WebServerGlueCgi(g_ksValidationKitDir, fHtmlOutput = True); + sUserAgent = oSrvGlue.getUserAgent(); + oSrvGlue.setHeaderField('Status', '401 Unauthorized to access the document'); + oSrvGlue.setHeaderField('WWW-authenticate', 'Basic realm="Test Manager"'); + if sUserAgent.startswith('Mozilla/') and sUserAgent.find('AppleWebKit/') > 0: + oSrvGlue.write('<p>Attempting to log out an Apple browser...</p>'); + else: + oSrvGlue.write('<p>Sorry, not sure this will work...</p>'); + oSrvGlue.write('<p>User-Agent:' + sUserAgent + '</p>'); + + oSrvGlue.write('<p><a href="%sadmin.py">Log in</a> under another user name.</p>' % + (oSrvGlue.getBaseUrl(),)) + + oSrvGlue.write('<hr/><p>debug info:</p>'); + oSrvGlue.debugInfoPage(); + oSrvGlue.flush(); + + return 0; + +if __name__ == '__main__': + sys.exit(main()); + diff --git a/src/VBox/ValidationKit/testmanager/cgi/rest.py b/src/VBox/ValidationKit/testmanager/cgi/rest.py new file mode 100755 index 00000000..89a5238c --- /dev/null +++ b/src/VBox/ValidationKit/testmanager/cgi/rest.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# $Id: rest.py $ + +""" +CGI - REST - sPath=path variant. +""" + +__copyright__ = \ +""" +Copyright (C) 2012-2023 Oracle and/or its affiliates. + +This file is part of VirtualBox base platform packages, as +available from https://www.virtualbox.org. + +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, in version 3 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, see <https://www.gnu.org/licenses>. + +The contents of this file may alternatively be used under the terms +of the Common Development and Distribution License Version 1.0 +(CDDL), a copy of it is provided in the "COPYING.CDDL" file included +in the VirtualBox distribution, in which case the provisions of the +CDDL are applicable instead of those of the GPL. + +You may elect to license modified versions of this file under the +terms and conditions of either the GPL or the CDDL or both. + +SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +""" +__version__ = "$Revision: 155244 $" + + +# Standard python imports. +import os +import sys + +# Only the main script needs to modify the path. +g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))); +sys.path.append(g_ksValidationKitDir); + +# Validation Kit imports. +from testmanager import config; +from testmanager.core.webservergluecgi import WebServerGlueCgi; +from testmanager.core.restdispatcher import RestMain, RestDispException; + + +def main(): + """ + Main function a la C/C++. Returns exit code. + """ + + oSrvGlue = WebServerGlueCgi(g_ksValidationKitDir, fHtmlOutput = False); + try: + oMain = RestMain(oSrvGlue); + oMain.dispatchRequest(); + oSrvGlue.flush(); + except RestDispException as oXcpt: + oSrvGlue.setStatus(oXcpt.iStatus); + oSrvGlue.setHeaderField('tm-error-message', str(oXcpt)); + oSrvGlue.write('error: ' + str(oXcpt)); + oSrvGlue.flush(); + except Exception as oXcpt: + return oSrvGlue.errorPage('Internal error: %s' % (str(oXcpt),), + sys.exc_info(), + config.g_ksTestBoxDispXpctLog); + + return 0; + +if __name__ == '__main__': + sys.exit(main()); + diff --git a/src/VBox/ValidationKit/testmanager/cgi/status.py b/src/VBox/ValidationKit/testmanager/cgi/status.py new file mode 100755 index 00000000..39c8af03 --- /dev/null +++ b/src/VBox/ValidationKit/testmanager/cgi/status.py @@ -0,0 +1,519 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# $Id: status.py $ + +""" +CGI - Administrator Web-UI. +""" + +__copyright__ = \ +""" +Copyright (C) 2012-2023 Oracle and/or its affiliates. + +This file is part of VirtualBox base platform packages, as +available from https://www.virtualbox.org. + +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, in version 3 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, see <https://www.gnu.org/licenses>. + +The contents of this file may alternatively be used under the terms +of the Common Development and Distribution License Version 1.0 +(CDDL), a copy of it is provided in the "COPYING.CDDL" file included +in the VirtualBox distribution, in which case the provisions of the +CDDL are applicable instead of those of the GPL. + +You may elect to license modified versions of this file under the +terms and conditions of either the GPL or the CDDL or both. + +SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +""" +__version__ = "$Revision: 155244 $" + + +# Standard python imports. +import os +import sys + +# Only the main script needs to modify the path. +g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))); +sys.path.append(g_ksValidationKitDir); + +# Validation Kit imports. +from testmanager import config; +from testmanager.core.webservergluecgi import WebServerGlueCgi; + +from common import constants; +from testmanager.core.base import TMExceptionBase; +from testmanager.core.db import TMDatabaseConnection; + + + +def timeDeltaToHours(oTimeDelta): + return oTimeDelta.days * 24 + oTimeDelta.seconds // 3600 + + +def testbox_data_processing(oDb): + testboxes_dict = {} + while True: + line = oDb.fetchOne(); + if line is None: + break; + testbox_name = line[0] + test_result = line[1] + oTimeDeltaSinceStarted = line[2] + test_box_os = line[3] + test_sched_group = line[4] + + # idle testboxes might have an assigned testsets, skipping them + if test_result not in g_kdTestStatuses: + continue + + testboxes_dict = dict_update(testboxes_dict, testbox_name, test_result) + + if "testbox_os" not in testboxes_dict[testbox_name]: + testboxes_dict[testbox_name].update({"testbox_os": test_box_os}) + + if "sched_group" not in testboxes_dict[testbox_name]: + testboxes_dict[testbox_name].update({"sched_group": test_sched_group}) + elif test_sched_group not in testboxes_dict[testbox_name]["sched_group"]: + testboxes_dict[testbox_name]["sched_group"] += "," + test_sched_group + + if test_result == "running": + testboxes_dict[testbox_name].update({"hours_running": timeDeltaToHours(oTimeDeltaSinceStarted)}) + + return testboxes_dict; + + +def os_results_separating(vb_dict, test_name, testbox_os, test_result): + if testbox_os == "linux": + dict_update(vb_dict, test_name + " / linux", test_result) + elif testbox_os == "win": + dict_update(vb_dict, test_name + " / windows", test_result) + elif testbox_os == "darwin": + dict_update(vb_dict, test_name + " / darwin", test_result) + elif testbox_os == "solaris": + dict_update(vb_dict, test_name + " / solaris", test_result) + else: + dict_update(vb_dict, test_name + " / other", test_result) + + +# const/immutable. +g_kdTestStatuses = { + 'running': 0, + 'success': 0, + 'skipped': 0, + 'bad-testbox': 0, + 'aborted': 0, + 'failure': 0, + 'timed-out': 0, + 'rebooted': 0, +} + +def dict_update(target_dict, key_name, test_result): + if key_name not in target_dict: + target_dict.update({key_name: g_kdTestStatuses.copy()}) + if test_result in g_kdTestStatuses: + target_dict[key_name][test_result] += 1 + return target_dict + + +def formatDataEntry(sKey, dEntry): + # There are variations in the first and second "columns". + if "hours_running" in dEntry: + sRet = "%s;%s;%s | running: %s;%s" \ + % (sKey, dEntry["testbox_os"], dEntry["sched_group"], dEntry["running"], dEntry["hours_running"]); + else: + if "testbox_os" in dEntry: + sRet = "%s;%s;%s" % (sKey, dEntry["testbox_os"], dEntry["sched_group"],); + else: + sRet = sKey; + sRet += " | running: %s" % (dEntry["running"],) + + # The rest is currently identical: + sRet += " | success: %s | skipped: %s | bad-testbox: %s | aborted: %s | failure: %s | timed-out: %s | rebooted: %s | \n" \ + % (dEntry["success"], dEntry["skipped"], dEntry["bad-testbox"], dEntry["aborted"], + dEntry["failure"], dEntry["timed-out"], dEntry["rebooted"],); + return sRet; + + +def format_data(dData, fSorted): + sRet = ""; + if not fSorted: + for sKey in dData: + sRet += formatDataEntry(sKey, dData[sKey]); + else: + for sKey in sorted(dData.keys()): + sRet += formatDataEntry(sKey, dData[sKey]); + return sRet; + +###### + +class StatusDispatcherException(TMExceptionBase): + """ + Exception class for TestBoxController. + """ + pass; # pylint: disable=unnecessary-pass + + +class StatusDispatcher(object): # pylint: disable=too-few-public-methods + """ + Status dispatcher class. + """ + + + def __init__(self, oSrvGlue): + """ + Won't raise exceptions. + """ + self._oSrvGlue = oSrvGlue; + self._sAction = None; # _getStandardParams / dispatchRequest sets this later on. + self._dParams = None; # _getStandardParams / dispatchRequest sets this later on. + self._asCheckedParams = []; + self._dActions = \ + { + 'MagicMirrorTestResults': self._actionMagicMirrorTestResults, + 'MagicMirrorTestBoxes': self._actionMagicMirrorTestBoxes, + }; + + def _getStringParam(self, sName, asValidValues = None, fStrip = False, sDefValue = None): + """ + Gets a string parameter (stripped). + + Raises exception if not found and no default is provided, or if the + value isn't found in asValidValues. + """ + if sName not in self._dParams: + if sDefValue is None: + raise StatusDispatcherException('%s parameter %s is missing' % (self._sAction, sName)); + return sDefValue; + sValue = self._dParams[sName]; + if fStrip: + sValue = sValue.strip(); + + if sName not in self._asCheckedParams: + self._asCheckedParams.append(sName); + + if asValidValues is not None and sValue not in asValidValues: + raise StatusDispatcherException('%s parameter %s value "%s" not in %s ' + % (self._sAction, sName, sValue, asValidValues)); + return sValue; + + def _getIntParam(self, sName, iMin = None, iMax = None, iDefValue = None): + """ + Gets a string parameter. + Raises exception if not found, not a valid integer, or if the value + isn't in the range defined by iMin and iMax. + """ + if sName not in self._dParams: + if iDefValue is None: + raise StatusDispatcherException('%s parameter %s is missing' % (self._sAction, sName)); + return iDefValue; + sValue = self._dParams[sName]; + try: + iValue = int(sValue, 0); + except: + raise StatusDispatcherException('%s parameter %s value "%s" cannot be convert to an integer' + % (self._sAction, sName, sValue)); + if sName not in self._asCheckedParams: + self._asCheckedParams.append(sName); + + if (iMin is not None and iValue < iMin) \ + or (iMax is not None and iValue > iMax): + raise StatusDispatcherException('%s parameter %s value %d is out of range [%s..%s]' + % (self._sAction, sName, iValue, iMin, iMax)); + return iValue; + + def _getBoolParam(self, sName, fDefValue = None): + """ + Gets a boolean parameter. + + Raises exception if not found and no default is provided, or if not a + valid boolean. + """ + sValue = self._getStringParam(sName, [ 'True', 'true', '1', 'False', 'false', '0'], sDefValue = str(fDefValue)); + return sValue in ('True', 'true', '1',); + + def _checkForUnknownParameters(self): + """ + Check if we've handled all parameters, raises exception if anything + unknown was found. + """ + + if len(self._asCheckedParams) != len(self._dParams): + sUnknownParams = ''; + for sKey in self._dParams: + if sKey not in self._asCheckedParams: + sUnknownParams += ' ' + sKey + '=' + self._dParams[sKey]; + raise StatusDispatcherException('Unknown parameters: ' + sUnknownParams); + + return True; + + def _connectToDb(self): + """ + Connects to the database. + + Returns (TMDatabaseConnection, (more later perhaps) ) on success. + Returns (None, ) on failure after sending the box an appropriate response. + May raise exception on DB error. + """ + return (TMDatabaseConnection(self._oSrvGlue.dprint),); + + def _actionMagicMirrorTestBoxes(self): + """ + Produces test result status for the magic mirror dashboard + """ + + # + # Parse arguments and connect to the database. + # + cHoursBack = self._getIntParam('cHours', 1, 24*14, 12); + fSorted = self._getBoolParam('fSorted', False); + self._checkForUnknownParameters(); + + # + # Get the data. + # + # Note! We're not joining on TestBoxesWithStrings.idTestBox = + # TestSets.idGenTestBox here because of indexes. This is + # also more consistent with the rest of the query. + # Note! The original SQL is slow because of the 'OR TestSets.tsDone' + # part, using AND and UNION is significatly faster because + # it matches the TestSetsGraphBoxIdx (index). + # + (oDb,) = self._connectToDb(); + if oDb is None: + return False; + + # + # some comments regarding select below: + # first part is about fetching all finished tests for last cHoursBack hours + # second part is fetching all tests which isn't done + # both old (running more than cHoursBack) and fresh (less than cHoursBack) ones + # 'cause we want to know if there's a hanging tests together with currently running + # + # there's also testsets without status at all, likely because disabled testboxes still have an assigned testsets + # + oDb.execute(''' +( SELECT TestBoxesWithStrings.sName, + TestSets.enmStatus, + CURRENT_TIMESTAMP - TestSets.tsCreated, + TestBoxesWithStrings.sOS, + SchedGroupNames.sSchedGroupNames + FROM ( + SELECT TestBoxesInSchedGroups.idTestBox AS idTestBox, + STRING_AGG(SchedGroups.sName, ',') AS sSchedGroupNames + FROM TestBoxesInSchedGroups + INNER JOIN SchedGroups + ON SchedGroups.idSchedGroup = TestBoxesInSchedGroups.idSchedGroup + WHERE TestBoxesInSchedGroups.tsExpire = 'infinity'::TIMESTAMP + AND SchedGroups.tsExpire = 'infinity'::TIMESTAMP + GROUP BY TestBoxesInSchedGroups.idTestBox + ) AS SchedGroupNames, + TestBoxesWithStrings + LEFT OUTER JOIN TestSets + ON TestSets.idTestBox = TestBoxesWithStrings.idTestBox + AND TestSets.tsCreated >= (CURRENT_TIMESTAMP - '%s hours'::interval) + AND TestSets.tsDone IS NOT NULL + WHERE TestBoxesWithStrings.tsExpire = 'infinity'::TIMESTAMP + AND SchedGroupNames.idTestBox = TestBoxesWithStrings.idTestBox +) UNION ( + SELECT TestBoxesWithStrings.sName, + TestSets.enmStatus, + CURRENT_TIMESTAMP - TestSets.tsCreated, + TestBoxesWithStrings.sOS, + SchedGroupNames.sSchedGroupNames + FROM ( + SELECT TestBoxesInSchedGroups.idTestBox AS idTestBox, + STRING_AGG(SchedGroups.sName, ',') AS sSchedGroupNames + FROM TestBoxesInSchedGroups + INNER JOIN SchedGroups + ON SchedGroups.idSchedGroup = TestBoxesInSchedGroups.idSchedGroup + WHERE TestBoxesInSchedGroups.tsExpire = 'infinity'::TIMESTAMP + AND SchedGroups.tsExpire = 'infinity'::TIMESTAMP + GROUP BY TestBoxesInSchedGroups.idTestBox + ) AS SchedGroupNames, + TestBoxesWithStrings + LEFT OUTER JOIN TestSets + ON TestSets.idTestBox = TestBoxesWithStrings.idTestBox + AND TestSets.tsDone IS NULL + WHERE TestBoxesWithStrings.tsExpire = 'infinity'::TIMESTAMP + AND SchedGroupNames.idTestBox = TestBoxesWithStrings.idTestBox +) +''', (cHoursBack, cHoursBack,)); + + + # + # Process, format and output data. + # + dResult = testbox_data_processing(oDb); + self._oSrvGlue.setContentType('text/plain'); + self._oSrvGlue.write(format_data(dResult, fSorted)); + + return True; + + def _actionMagicMirrorTestResults(self): + """ + Produces test result status for the magic mirror dashboard + """ + + # + # Parse arguments and connect to the database. + # + sBranch = self._getStringParam('sBranch'); + cHoursBack = self._getIntParam('cHours', 1, 24*14, 6); ## @todo why 6 hours here and 12 for test boxes? + fSorted = self._getBoolParam('fSorted', False); + self._checkForUnknownParameters(); + + # + # Get the data. + # + # Note! These queries should be joining TestBoxesWithStrings and TestSets + # on idGenTestBox rather than on idTestBox and tsExpire=inf, but + # we don't have any index matching those. So, we'll ignore tests + # performed by deleted testboxes for the present as that doesn't + # happen often and we want the ~1000x speedup. + # + (oDb,) = self._connectToDb(); + if oDb is None: + return False; + + if sBranch == 'all': + oDb.execute(''' +SELECT TestSets.enmStatus, + TestCases.sName, + TestBoxesWithStrings.sOS +FROM TestSets +INNER JOIN TestCases + ON TestCases.idGenTestCase = TestSets.idGenTestCase +INNER JOIN TestBoxesWithStrings + ON TestBoxesWithStrings.idTestBox = TestSets.idTestBox + AND TestBoxesWithStrings.tsExpire = 'infinity'::TIMESTAMP +WHERE TestSets.tsCreated >= (CURRENT_TIMESTAMP - '%s hours'::interval) +''', (cHoursBack,)); + else: + oDb.execute(''' +SELECT TestSets.enmStatus, + TestCases.sName, + TestBoxesWithStrings.sOS +FROM TestSets +INNER JOIN BuildCategories + ON BuildCategories.idBuildCategory = TestSets.idBuildCategory + AND BuildCategories.sBranch = %s +INNER JOIN TestCases + ON TestCases.idGenTestCase = TestSets.idGenTestCase +INNER JOIN TestBoxesWithStrings + ON TestBoxesWithStrings.idTestBox = TestSets.idTestBox + AND TestBoxesWithStrings.tsExpire = 'infinity'::TIMESTAMP +WHERE TestSets.tsCreated >= (CURRENT_TIMESTAMP - '%s hours'::interval) +''', (sBranch, cHoursBack,)); + + # Process the data + dResult = {}; + while True: + aoRow = oDb.fetchOne(); + if aoRow is None: + break; + os_results_separating(dResult, aoRow[1], aoRow[2], aoRow[0]) # save all test results + + # Format and output it. + self._oSrvGlue.setContentType('text/plain'); + self._oSrvGlue.write(format_data(dResult, fSorted)); + + return True; + + def _getStandardParams(self, dParams): + """ + Gets the standard parameters and validates them. + + The parameters are returned as a tuple: sAction, (more later, maybe) + Note! the sTextBoxId can be None if it's a SIGNON request. + + Raises StatusDispatcherException on invalid input. + """ + # + # Get the action parameter and validate it. + # + if constants.tbreq.ALL_PARAM_ACTION not in dParams: + raise StatusDispatcherException('No "%s" parameter in request (params: %s)' + % (constants.tbreq.ALL_PARAM_ACTION, dParams,)); + sAction = dParams[constants.tbreq.ALL_PARAM_ACTION]; + + if sAction not in self._dActions: + raise StatusDispatcherException('Unknown action "%s" in request (params: %s; action: %s)' + % (sAction, dParams, self._dActions)); + # + # Update the list of checked parameters. + # + self._asCheckedParams.extend([constants.tbreq.ALL_PARAM_ACTION,]); + + return (sAction,); + + def dispatchRequest(self): + """ + Dispatches the incoming request. + + Will raise StatusDispatcherException on failure. + """ + + # + # Must be a GET request. + # + try: + sMethod = self._oSrvGlue.getMethod(); + except Exception as oXcpt: + raise StatusDispatcherException('Error retriving request method: %s' % (oXcpt,)); + if sMethod != 'GET': + raise StatusDispatcherException('Error expected POST request not "%s"' % (sMethod,)); + + # + # Get the parameters and checks for duplicates. + # + try: + dParams = self._oSrvGlue.getParameters(); + except Exception as oXcpt: + raise StatusDispatcherException('Error retriving parameters: %s' % (oXcpt,)); + for sKey in dParams.keys(): + if len(dParams[sKey]) > 1: + raise StatusDispatcherException('Parameter "%s" is given multiple times: %s' % (sKey, dParams[sKey])); + dParams[sKey] = dParams[sKey][0]; + self._dParams = dParams; + + # + # Get+validate the standard action parameters and dispatch the request. + # + (self._sAction, ) = self._getStandardParams(dParams); + return self._dActions[self._sAction](); + + +def main(): + """ + Main function a la C/C++. Returns exit code. + """ + + oSrvGlue = WebServerGlueCgi(g_ksValidationKitDir, fHtmlOutput = False); + try: + oDisp = StatusDispatcher(oSrvGlue); + oDisp.dispatchRequest(); + oSrvGlue.flush(); + except Exception as oXcpt: + return oSrvGlue.errorPage('Internal error: %s' % (str(oXcpt),), sys.exc_info()); + + return 0; + +if __name__ == '__main__': + if config.g_kfProfileAdmin: + from testmanager.debug import cgiprofiling; + sys.exit(cgiprofiling.profileIt(main)); + else: + sys.exit(main()); + diff --git a/src/VBox/ValidationKit/testmanager/cgi/testboxdisp.py b/src/VBox/ValidationKit/testmanager/cgi/testboxdisp.py new file mode 100755 index 00000000..c5c704bb --- /dev/null +++ b/src/VBox/ValidationKit/testmanager/cgi/testboxdisp.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# $Id: testboxdisp.py $ + +""" +CGI - TestBox Interaction (see testboxscript or the other party). +""" + +__copyright__ = \ +""" +Copyright (C) 2012-2023 Oracle and/or its affiliates. + +This file is part of VirtualBox base platform packages, as +available from https://www.virtualbox.org. + +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, in version 3 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, see <https://www.gnu.org/licenses>. + +The contents of this file may alternatively be used under the terms +of the Common Development and Distribution License Version 1.0 +(CDDL), a copy of it is provided in the "COPYING.CDDL" file included +in the VirtualBox distribution, in which case the provisions of the +CDDL are applicable instead of those of the GPL. + +You may elect to license modified versions of this file under the +terms and conditions of either the GPL or the CDDL or both. + +SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +""" +__version__ = "$Revision: 155244 $" + + +# Standard python imports. +import os +import sys + +# Only the main script needs to modify the path. +g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))); +sys.path.append(g_ksValidationKitDir); + +# Validation Kit imports. +from testmanager import config; +from testmanager.core.webservergluecgi import WebServerGlueCgi; +from testmanager.core.testboxcontroller import TestBoxController; + + +def main(): + """ + Main function a la C/C++. Returns exit code. + """ + + oSrvGlue = WebServerGlueCgi(g_ksValidationKitDir, fHtmlOutput = False); + oCtrl = TestBoxController(oSrvGlue); + try: + oCtrl.dispatchRequest() + oSrvGlue.flush(); + except Exception as oXcpt: + return oSrvGlue.errorPage('Internal error: %s' % (str(oXcpt),), + sys.exc_info(), + config.g_ksTestBoxDispXpctLog); + return 0; + +if __name__ == '__main__': + sys.exit(main()); + |