testbox.py revision cf22150eaeeb72431bf1cf65c309a431454fb22b
# -*- coding: utf-8 -*-
# $Id$
"""
Test Manager - TestBox.
"""
__copyright__ = \
"""
Copyright (C) 2012-2014 Oracle Corporation
This file is part of VirtualBox Open Source Edition (OSE), as
available from http://www.virtualbox.org. This file is free software;
General Public License (GPL) as published by the Free Software
Foundation, in version 2 as it comes in the "COPYING" file of the
VirtualBox OSE distribution. VirtualBox OSE is distributed in the
hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
The contents of this file may alternatively be used under the terms
of the Common Development and Distribution License Version 1.0
(CDDL) only, as it comes in the "COPYING.CDDL" file of the
VirtualBox OSE 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.
"""
__version__ = "$Revision$"
# Standard python imports.
import unittest;
# Validation Kit imports.
from testmanager.core.base import ModelDataBase, ModelDataBaseTestCase, ModelLogicBase, TMExceptionBase, \
# pylint: disable=C0103
"""
TestBox Data.
"""
## LomKind_T
ksLomKind_None = 'none';
ksLomKind_ILOM = 'ilom';
ksLomKind_ELOM = 'elom';
ksLomKind_AppleXserveLom = 'apple-xserver-lom';
kaoLomKindDescs = \
[
];
## TestBoxCmd_T
ksTestBoxCmd_None = 'none';
ksTestBoxCmd_Abort = 'abort';
ksTestBoxCmd_Reboot = 'reboot';
ksTestBoxCmd_Upgrade = 'upgrade';
ksTestBoxCmd_UpgradeAndReboot = 'upgrade-and-reboot';
ksTestBoxCmd_Special = 'special';
kasTestBoxCmdValues = [ ksTestBoxCmd_None, ksTestBoxCmd_Abort, ksTestBoxCmd_Reboot, ksTestBoxCmd_Upgrade,
[
];
ksIdAttr = 'idTestBox';
ksIdGenAttr = 'idGenTestBox';
ksParam_idTestBox = 'TestBox_idTestBox';
ksParam_tsEffective = 'TestBox_tsEffective';
ksParam_tsExpire = 'TestBox_tsExpire';
ksParam_uidAuthor = 'TestBox_uidAuthor';
ksParam_idGenTestBox = 'TestBox_idGenTestBox';
ksParam_ip = 'TestBox_ip';
ksParam_uuidSystem = 'TestBox_uuidSystem';
ksParam_sName = 'TestBox_sName';
ksParam_sDescription = 'TestBox_sDescription';
ksParam_idSchedGroup = 'TestBox_idSchedGroup';
ksParam_fEnabled = 'TestBox_fEnabled';
ksParam_enmLomKind = 'TestBox_enmLomKind';
ksParam_ipLom = 'TestBox_ipLom';
ksParam_pctScaleTimeout = 'TestBox_pctScaleTimeout';
ksParam_sOs = 'TestBox_sOs';
ksParam_sOsVersion = 'TestBox_sOsVersion';
ksParam_sCpuVendor = 'TestBox_sCpuVendor';
ksParam_sCpuArch = 'TestBox_sCpuArch';
ksParam_sCpuName = 'TestBox_sCpuName';
ksParam_lCpuRevision = 'TestBox_lCpuRevision';
ksParam_cCpus = 'TestBox_cCpus';
ksParam_fCpuHwVirt = 'TestBox_fCpuHwVirt';
ksParam_fCpuNestedPaging = 'TestBox_fCpuNestedPaging';
ksParam_fCpu64BitGuest = 'TestBox_fCpu64BitGuest';
ksParam_fChipsetIoMmu = 'TestBox_fChipsetIoMmu';
ksParam_cMbMemory = 'TestBox_cMbMemory';
ksParam_cMbScratch = 'TestBox_cMbScratch';
ksParam_sReport = 'TestBox_sReport';
ksParam_iTestBoxScriptRev = 'TestBox_iTestBoxScriptRev';
ksParam_iPythonHexVersion = 'TestBox_iPythonHexVersion';
ksParam_enmPendingCmd = 'TestBox_enmPendingCmd';
kasAllowNullAttributes = ['idTestBox', 'tsEffective', 'tsExpire', 'uidAuthor', 'idGenTestBox', 'sDescription',
'ipLom', 'sOs', 'sOsVersion', 'sCpuVendor', 'sCpuArch', 'sCpuName', 'lCpuRevision', 'cCpus',
'fCpuHwVirt', 'fCpuNestedPaging', 'fCpu64BitGuest', 'fChipsetIoMmu', 'cMbMemory',
'cMbScratch', 'sReport', 'iTestBoxScriptRev', 'iPythonHexVersion' ];
kiMin_pctScaleTimeout = 11;
kiMax_pctScaleTimeout = 19999;
kcchMax_sReport = 65535;
#
# Initialize with defaults.
# See the database for explanations of each of these fields.
#
self.tsEffective = None;
self.idGenTestBox = None;
self.uuidSystem = None;
self.sDescription = None;
self.sOsVersion = None;
self.sCpuVendor = None;
self.lCpuRevision = None;
"""
Internal worker for initFromDbWithId and initFromDbWithGenId as well as
from TestBoxLogic. Expecting a SELECT * FROM TestBoxes result.
"""
if aoRow is None:
raise TMExceptionBase('TestBox not found.');
return self;
"""
Initialize the object from the database.
"""
'SELECT *\n'
'FROM TestBoxes\n'
'WHERE idTestBox = %s\n'
if aoRow is None:
raise TMExceptionBase('idTestBox=%s not found (tsNow=%s sPeriodBack=%s)' % (idTestBox, tsNow, sPeriodBack,));
"""
Initialize the object from the database.
"""
'FROM TestBoxes\n'
'WHERE idGenTestBox = %s\n'
, (idGenTestBox, ) );
# Override to do extra ipLom checks.
return dErrors;
def formatPythonVersion(self):
"""
Unbuttons the version number and formats it as a version string.
"""
if self.iPythonHexVersion is None:
return 'N/A';
return 'v%d.%d.%d.%d' \
def getCpuFamily(self):
""" Returns the CPU family for a x86 or amd64 testboxes."""
if self.lCpuRevision is None:
return 0;
def getCpuModel(self):
""" Returns the CPU model for a x86 or amd64 testboxes."""
if self.lCpuRevision is None:
return 0;
def getCpuStepping(self):
""" Returns the CPU stepping for a x86 or amd64 testboxes."""
if self.lCpuRevision is None:
return 0;
class TestBoxLogic(ModelLogicBase):
"""
TestBox logic.
"""
"""
Tries to fetch a testbox by its UUID alone.
"""
'FROM TestBoxes\n'
'WHERE uuidSystem = %s\n'
' AND tsExpire = \'infinity\'::timestamp\n'
'ORDER BY tsEffective DESC\n',
(sTestBoxUuid,));
return None;
oData = TestBoxData();
return oData;
"""
Fetches testboxes for listing.
Returns an array (list) of TestBoxData items, empty list if none. The
TestBoxData instances have an extra oStatus member that is either None or
a TestBoxStatusData instance, and a member tsCurrent holding
CURRENT_TIMESTAMP.
Raises exception on error.
"""
if tsNow is None:
'FROM TestBoxes\n'
'LEFT OUTER JOIN TestBoxStatuses ON (\n'
' TestBoxStatuses.idTestBox = TestBoxes.idTestBox )\n'
'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
'ORDER BY sName\n'
'LIMIT %s OFFSET %s\n'
else:
'FROM TestBoxes\n'
'LEFT OUTER JOIN TestBoxStatuses ON (\n'
' TestBoxStatuses.idTestBox = TestBoxes.idTestBox )\n'
'WHERE tsExpire > %s\n'
' AND tsEffective <= %s\n'
'ORDER BY sName\n'
'LIMIT %s OFFSET %s\n'
aoRows = [];
if aoOne[31] is not None:
return aoRows;
"""
Fetches change log entries for a testbox.
Returns an array of ChangeLogEntry instance and an indicator whether
there are more entries.
Raises exception on error.
"""
if tsNow is None:
'FROM TestBoxes\n'
'LEFT OUTER JOIN Users \n'
' ON ( TestBoxes.uidAuthor = Users.uid\n'
' AND Users.tsEffective <= TestBoxes.tsEffective\n'
' AND Users.tsExpire > TestBoxes.tsEffective)\n'
'WHERE TestBoxes.tsEffective <= %s\n'
' AND TestBoxes.idTestBox = %s\n'
'ORDER BY TestBoxes.tsExpire DESC\n'
'LIMIT %s OFFSET %s\n'
aoRows = [];
# Calculate the changes.
aoEntries = [];
aoChanges = [];
aoEntries.append(ChangeLogEntry(oNew.uidAuthor, sAuthor, oNew.tsEffective, oNew.tsExpire, oNew, oOld, aoChanges));
# If we're at the end of the log, add the initial entry.
aoEntries.append(ChangeLogEntry(oNew.uidAuthor, aoRows[-1][1], oNew.tsEffective, oNew.tsExpire, oNew, None, []));
"""
Creates a testbox in the database.
Returns the testbox ID, testbox generation ID and effective timestamp
of the created testbox on success. Throws error on failure.
"""
' idTestBox,\n'
' tsEffective,\n'
' tsExpire,\n'
' uidAuthor,\n'
' idGenTestBox,\n'
' ip,\n'
' uuidSystem,\n'
' sName,\n'
' sDescription,\n'
' idSchedGroup,\n'
' fEnabled,\n'
' enmLomKind,\n'
' ipLom,\n'
' pctScaleTimeout,\n'
' sOs,\n'
' sOsVersion,\n'
' sCpuVendor,\n'
' sCpuArch,\n'
' sCpuName,\n'
' lCpuRevision,\n'
' cCpus,\n'
' fCpuHwVirt,\n'
' fCpuNestedPaging,\n'
' fCpu64BitGuest,\n'
' fChipsetIoMmu,\n'
' cMbMemory,\n'
' cMbScratch,\n'
' sReport,\n'
' iTestBoxScriptRev,\n'
' iPythonHexVersion,\n'
' enmPendingCmd\n'
' )'
'VALUES (\n'
' DEFAULT,\n'
' CURRENT_TIMESTAMP,\n'
' DEFAULT,\n'
' %s,\n' # uidAuthor
' DEFAULT,\n'
' %s,\n' # ip
' %s,\n' # uuidSystem
' %s,\n' # sName
' %s,\n' # sDescription
' %s,\n' # idSchedGroup
' %s,\n' # fEnabled
' %s,\n' # enmLomKind
' %s,\n' # ipLom
' %s,\n' # pctScaleTimeout
' %s,\n' # sOs
' %s,\n' # sOsVersion
' %s,\n' # sCpuVendor
' %s,\n' # sCpuArch
' %s,\n' # sCpuName
' %s,\n' # lCpuRevision
' %s,\n' # cCpus
' %s,\n' # fCpuHwVirt
' %s,\n' # fCpuNestedPaging
' %s,\n' # fCpu64BitGuest
' %s,\n' # fChipsetIoMmu
' %s,\n' # cMbMemory
' %s,\n' # cMbScratch
' %s,\n' # sReport
' %s,\n' # iTestBoxScriptRev
' %s,\n' # iPythonHexVersion
' %s\n' # enmPendingCmd
' )\n'
'RETURNING idTestBox, idGenTestBox, tsEffective'
, (uidAuthor,
)
);
"""
Data edit update, web UI is the primary user.
Returns the new generation ID and effective date.
"""
## @todo check if the data changed.
'SET tsExpire = CURRENT_TIMESTAMP\n'
'WHERE idGenTestBox = %s\n'
' AND tsExpire = \'infinity\'::timestamp\n'
'RETURNING tsExpire\n',
(oData.idGenTestBox,));
try:
# Would be easier to do this using an insert or update hook, I think. Much easier.
' idGenTestBox,\n'
' idTestBox,\n'
' tsEffective,\n'
' uidAuthor,\n'
' ip,\n'
' uuidSystem,\n'
' sName,\n'
' sDescription,\n'
' idSchedGroup,\n'
' fEnabled,\n'
' enmLomKind,\n'
' ipLom,\n'
' pctScaleTimeout,\n'
' sOs,\n'
' sOsVersion,\n'
' sCpuVendor,\n'
' sCpuArch,\n'
' sCpuName,\n'
' lCpuRevision,\n'
' cCpus,\n'
' fCpuHwVirt,\n'
' fCpuNestedPaging,\n'
' fCpu64BitGuest,\n'
' fChipsetIoMmu,\n'
' cMbMemory,\n'
' cMbScratch,\n'
' iTestBoxScriptRev,\n'
' iPythonHexVersion,\n'
' enmPendingCmd\n'
' )\n'
'SELECT NEXTVAL(\'TestBoxGenIdSeq\'),\n'
' idTestBox,\n'
' %s,\n' # tsEffective
' %s,\n' # uidAuthor
' %s,\n' # ip
' %s,\n' # uuidSystem
' %s,\n' # sName
' %s,\n' # sDescription
' %s,\n' # idSchedGroup
' %s,\n' # fEnabled
' %s,\n' # enmLomKind
' %s,\n' # ipLom
' %s,\n' # pctScaleTimeout
' sOs,\n'
' sOsVersion,\n'
' sCpuVendor,\n'
' sCpuArch,\n'
' sCpuName,\n'
' lCpuRevision,\n'
' cCpus,\n'
' fCpuHwVirt,\n'
' fCpuNestedPaging,\n'
' fCpu64BitGuest,\n'
' fChipsetIoMmu,\n'
' cMbMemory,\n'
' cMbScratch,\n'
' iTestBoxScriptRev,\n'
' iPythonHexVersion,\n'
' %s\n' # enmPendingCmd
'FROM TestBoxes\n'
'WHERE idGenTestBox = %s\n'
'RETURNING idGenTestBox, tsEffective'
, (tsEffective,
));
if aRow is None:
raise TMExceptionBase('Insert failed? oRow=None');
except:
raise;
return (idGenTestBox, tsEffective);
def updateOnSignOn(self, idTestBox, idGenTestBox, sTestBoxAddr, sOs, sOsVersion, # pylint: disable=R0913,R0914
"""
Update the testbox attributes automatically on behalf of the testbox script.
Returns the new generation id on success, raises an exception on failure.
"""
try:
# Would be easier to do this using an insert or update hook, I think. Much easier.
'SET tsExpire = CURRENT_TIMESTAMP\n'
'WHERE idGenTestBox = %s\n'
' AND tsExpire = \'infinity\'::timestamp\n'
'RETURNING tsExpire\n',
(idGenTestBox,));
' idGenTestBox,\n'
' idTestBox,\n'
' tsEffective,\n'
' uidAuthor,\n'
' ip,\n'
' uuidSystem,\n'
' sName,\n'
' sDescription,\n'
' idSchedGroup,\n'
' fEnabled,\n'
' enmLomKind,\n'
' ipLom,\n'
' pctScaleTimeout,\n'
' sOs,\n'
' sOsVersion,\n'
' sCpuVendor,\n'
' sCpuArch,\n'
' sCpuName,\n'
' lCpuRevision,\n'
' cCpus,\n'
' fCpuHwVirt,\n'
' fCpuNestedPaging,\n'
' fCpu64BitGuest,\n'
' fChipsetIoMmu,\n'
' cMbMemory,\n'
' cMbScratch,\n'
' sReport,\n'
' iTestBoxScriptRev,\n'
' iPythonHexVersion,\n'
' enmPendingCmd\n'
' )\n'
'SELECT NEXTVAL(\'TestBoxGenIdSeq\'),\n'
' %s,\n'
' %s,\n'
' NULL,\n' # uidAuthor
' %s,\n'
' uuidSystem,\n'
' sName,\n'
' sDescription,\n'
' idSchedGroup,\n'
' fEnabled,\n'
' enmLomKind,\n'
' ipLom,\n'
' pctScaleTimeout,\n'
' %s,\n' # sOs
' %s,\n' # sOsVersion
' %s,\n' # sCpuVendor
' %s,\n' # sCpuArch
' %s,\n' # sCpuName
' %s,\n' # lCpuRevision
' %s,\n' # cCpus
' %s,\n' # fCpuHwVirt
' %s,\n' # fCpuNestedPaging
' %s,\n' # fCpu64BitGuest
' %s,\n' # fChipsetIoMmu
' %s,\n' # cMbMemory
' %s,\n' # cMbScratch
' %s,\n' # sReport
' %s,\n' # iTestBoxScriptRev
' %s,\n' # iPythonHexVersion
' enmPendingCmd\n'
'FROM TestBoxes\n'
'WHERE idGenTestBox = %s\n'
'RETURNING idGenTestBox'
, (idTestBox,
sOs,
));
except:
raise;
return idGenTestBox;
"""
Sets or resets the pending command on a testbox.
Returns (idGenTestBox, tsEffective) of the new row.
"""
try:
# Would be easier to do this using an insert or update hook, I think. Much easier.
'SET tsExpire = CURRENT_TIMESTAMP\n'
'WHERE idTestBox = %s\n'
' AND tsExpire = \'infinity\'::timestamp\n'
' AND enmPendingCmd = %s\n'
'RETURNING tsExpire\n',
(idTestBox, sOldCommand,));
' idGenTestBox,\n'
' idTestBox,\n'
' tsEffective,\n'
' uidAuthor,\n'
' ip,\n'
' uuidSystem,\n'
' sName,\n'
' sDescription,\n'
' idSchedGroup,\n'
' fEnabled,\n'
' enmLomKind,\n'
' ipLom,\n'
' pctScaleTimeout,\n'
' sOs,\n'
' sOsVersion,\n'
' sCpuVendor,\n'
' sCpuArch,\n'
' sCpuName,\n'
' lCpuRevision,\n'
' cCpus,\n'
' fCpuHwVirt,\n'
' fCpuNestedPaging,\n'
' fCpu64BitGuest,\n'
' fChipsetIoMmu,\n'
' cMbMemory,\n'
' cMbScratch,\n'
' sReport,\n'
' iTestBoxScriptRev,\n'
' iPythonHexVersion,\n'
' enmPendingCmd\n'
' )\n'
'SELECT NEXTVAL(\'TestBoxGenIdSeq\'),\n'
' %s,\n' # idTestBox
' %s,\n' # tsEffective
' %s,\n' # uidAuthor
' ip,\n'
' uuidSystem,\n'
' sName,\n'
' sDescription,\n'
' idSchedGroup,\n'
' fEnabled,\n'
' enmLomKind,\n'
' ipLom,\n'
' pctScaleTimeout,\n'
' sOs,\n'
' sOsVersion,\n'
' sCpuVendor,\n'
' sCpuArch,\n'
' sCpuName,\n'
' lCpuRevision,\n'
' cCpus,\n'
' fCpuHwVirt,\n'
' fCpuNestedPaging,\n'
' fCpu64BitGuest,\n'
' fChipsetIoMmu,\n'
' cMbMemory,\n'
' cMbScratch,\n'
' sReport,\n'
' iTestBoxScriptRev,\n'
' iPythonHexVersion,\n'
' %s\n' # enmPendingCmd
'FROM TestBoxes\n'
'WHERE idTestBox = %s\n'
' AND tsExpire = %s\n'
' AND enmPendingCmd = %s\n'
'RETURNING idGenTestBox'
, (idTestBox,
));
except:
raise;
return (idGenTestBox, tsEffective);
"""
Retrieve list of all registered Test Box records from DB.
"""
'FROM TestBoxes\n'
'WHERE tsExpire=\'infinity\'::timestamp;')
aoRet = []
return aoRet
""" Historizes the current entry. """
if tsExpire is None:
'SET tsExpire = CURRENT_TIMESTAMP,\n'
' uidAuthor = %s\n'
'WHERE idTestBox = %s\n'
' AND tsExpire = \'infinity\'::TIMESTAMP\n'
else:
'SET tsExpire = %s,\n'
' uidAuthor = %s\n'
'WHERE idTestBox = %s\n'
' AND tsExpire = \'infinity\'::TIMESTAMP\n'
return True;
"""
Delete user account
"""
_ = fCascade;
if fRc:
return fRc
#
# Unit testing.
#
# pylint: disable=C0111
if __name__ == '__main__':
# not reached.