cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# -*- coding: utf-8 -*-
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncTest Manager WUI - TestBox.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncCopyright (C) 2012-2014 Oracle Corporation
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncThis file is part of VirtualBox Open Source Edition (OSE), as
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncavailable from http://www.virtualbox.org. This file is free software;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncyou can redistribute it and/or modify it under the terms of the GNU
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncGeneral Public License (GPL) as published by the Free Software
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncFoundation, in version 2 as it comes in the "COPYING" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncVirtualBox OSE distribution. VirtualBox OSE is distributed in the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsynchope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncThe contents of this file may alternatively be used under the terms
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncof the Common Development and Distribution License Version 1.0
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync(CDDL) only, as it comes in the "COPYING.CDDL" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncVirtualBox OSE distribution, in which case the provisions of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncCDDL are applicable instead of those of the GPL.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncYou may elect to license modified versions of this file under the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncterms and conditions of either the GPL or the CDDL or both.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Standard python imports.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Validation Kit imports.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.webui.wuicontentbase import WuiListContentWithActionBase, WuiFormContentBase, WuiLinkBase, WuiSvnLink, \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.db import TMDatabaseConnection;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.schedgroup import SchedGroupLogic, SchedGroupData;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.db import isDbTimestampInfinity;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WUI TestBox Form Content Generator.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oData.uuidSystem is not None and len(oData.uuidSystem) > 10:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTitle = 'Edit TestBox - %s (#%s)' % (oData.sName, oData.idTestBox);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTitle = 'TestBox - %s (#%s)' % (oData.sName, oData.idTestBox);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiFormContentBase.__init__(self, oData, sMode, 'TestBox', oDisp, sTitle);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Try enter sName as hostname (no domain) when creating the testbox.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync (self._oData.sName, _, _) = socket.gethostbyaddr(self._oData.ip);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addIntRO( TestBoxData.ksParam_idTestBox, oData.idTestBox, 'TestBox ID');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addIntRO( TestBoxData.ksParam_idGenTestBox, oData.idGenTestBox, 'TestBox generation ID');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addTimestampRO(TestBoxData.ksParam_tsEffective, oData.tsEffective, 'Last changed');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addTimestampRO(TestBoxData.ksParam_tsExpire, oData.tsExpire, 'Expires (excl)');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addIntRO( TestBoxData.ksParam_uidAuthor, oData.uidAuthor, 'Changed by UID');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addText( TestBoxData.ksParam_ip, oData.ip, 'TestBox IP Address');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addUuid( TestBoxData.ksParam_uuidSystem, oData.uuidSystem, 'TestBox System/Firmware UUID');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addText( TestBoxData.ksParam_sName, oData.sName, 'TestBox Name');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addText( TestBoxData.ksParam_sDescription, oData.sDescription, 'TestBox Description');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addComboBox( TestBoxData.ksParam_idSchedGroup, oData.idSchedGroup, 'Scheduling Group',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync SchedGroupLogic(TMDatabaseConnection()).getSchedGroupsForCombo());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addCheckBox( TestBoxData.ksParam_fEnabled, oData.fEnabled, 'Enabled');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addComboBox( TestBoxData.ksParam_enmLomKind, oData.enmLomKind, 'Lights-out-management',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addText( TestBoxData.ksParam_ipLom, oData.ipLom, 'Lights-out-management IP Address');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addInt( TestBoxData.ksParam_pctScaleTimeout, oData.pctScaleTimeout, 'Timeout scale factor (%)');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @todo Pretty format the read-only fields and use hidden fields for
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # passing the actual values. (Yes, we need the values so we can
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # display the form correctly on input error.)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addTextRO( TestBoxData.ksParam_sOs, oData.sOs, 'TestBox OS');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addTextRO( TestBoxData.ksParam_sOsVersion, oData.sOsVersion, 'TestBox OS version');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addTextRO( TestBoxData.ksParam_sCpuArch, oData.sCpuArch, 'TestBox OS kernel architecture');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addTextRO( TestBoxData.ksParam_sCpuVendor, oData.sCpuVendor, 'TestBox CPU vendor');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addTextRO( TestBoxData.ksParam_sCpuName, oData.sCpuName, 'TestBox CPU name');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addTextRO( TestBoxData.ksParam_lCpuRevision, '%#x' % (oData.lCpuRevision,), 'TestBox CPU revision',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (oData.getCpuFamily(), oData.getCpuModel(), oData.getCpuStepping(),),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addLongRO( TestBoxData.ksParam_lCpuRevision, oData.lCpuRevision, 'TestBox CPU revision');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addIntRO( TestBoxData.ksParam_cCpus, oData.cCpus, 'Number of CPUs, cores and threads');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addCheckBoxRO( TestBoxData.ksParam_fCpuHwVirt, oData.fCpuHwVirt, 'VT-x or AMD-V supported');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addCheckBoxRO( TestBoxData.ksParam_fCpuNestedPaging, oData.fCpuNestedPaging, 'Nested paging supported');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addCheckBoxRO( TestBoxData.ksParam_fCpu64BitGuest, oData.fCpu64BitGuest, '64-bit guest supported');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addCheckBoxRO( TestBoxData.ksParam_fChipsetIoMmu, oData.fChipsetIoMmu, 'I/O MMU supported');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addMultilineTextRO(TestBoxData.ksParam_sReport, oData.sReport, 'Hardware/software report');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addLongRO( TestBoxData.ksParam_cMbMemory, oData.cMbMemory, 'Installed RAM size (MB)');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addLongRO( TestBoxData.ksParam_cMbScratch, oData.cMbScratch, 'Available scratch space (MB)');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addIntRO( TestBoxData.ksParam_iTestBoxScriptRev, oData.iTestBoxScriptRev,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'TestBox Script SVN revision');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #if not self.isAttributeNull(''):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # sHexVer = '%s.%s.%.%s' % (oData.iPythonHexVersion >> 24, (oData.iPythonHexVersion >> 16) & 0xff,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # (oData.iPythonHexVersion >> 8) & 0xff, oData.iPythonHexVersion & 0xff);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # sHexVer = str(oData.iPythonHexVersion);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addIntRO( TestBoxData.ksParam_iPythonHexVersion, oData.iPythonHexVersion,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'Python version (hex)');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addComboBox(TestBoxData.ksParam_enmPendingCmd, oData.enmPendingCmd, 'Pending command',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addComboBoxRO(TestBoxData.ksParam_enmPendingCmd, oData.enmPendingCmd, 'Pending command',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oForm.addSubmit('Create TestBox' if self._sMode == WuiFormContentBase.ksMode_Add else 'Change TestBox');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WUI TestBox List Content Generator.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## Descriptors for the combo box.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def __init__(self, aoEntries, iPage, cItemsPerPage, tsEffective, fnDPrint, oDisp):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiListContentWithActionBase.__init__(self, aoEntries, iPage, cItemsPerPage, tsEffective,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTitle = 'TestBoxes', sId = 'users', fnDPrint = fnDPrint, oDisp = oDisp);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._asColumnHeaders.extend([ 'Name', 'LOM', 'Status',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'Actions' ]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._asColumnAttribs.extend([ 'align="center"', 'align="center"', 'align="center"',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'align="center"', 'align="center"', 'align="center"', 'align="center"',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync '', '', '', 'align="right"', 'align="right"', 'align="right"',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'align="center"' ]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoActions = list(self.kasTestBoxActionDescs);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoSchedGroups = SchedGroupLogic(self._oDisp.getDb()).fetchOrderedByName();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._aoActions.append([ 'setgroup-%u' % (oSchedGroup.idSchedGroup,),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'Migrate to group %s (#%u)' % (oSchedGroup.sName, oSchedGroup.idSchedGroup,),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._dSchedGroups[oSchedGroup.idSchedGroup] = oSchedGroup;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._sCheckboxName = TestBoxData.ksParam_idTestBox;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _formatListEntry(self, iEntry): # pylint: disable=R0914
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Lights outs managment.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oEntry.enmLomKind == TestBoxData.ksLomKind_ILOM:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoLom = [ WuiLinkBase('ILOM', 'https://%s/' % (oEntry.ipLom,), fBracketed = False), ];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync elif oEntry.enmLomKind == TestBoxData.ksLomKind_ELOM:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoLom = [ WuiLinkBase('ELOM', 'http://%s/' % (oEntry.ipLom,), fBracketed = False), ];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync elif oEntry.enmLomKind == TestBoxData.ksLomKind_AppleXserveLom:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync elif oEntry.enmLomKind == TestBoxData.ksLomKind_None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoLom = [ 'Unexpected enmLomKind value "%s"' % (oEntry.enmLomKind,) ];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oEntry.enmLomKind in [ TestBoxData.ksLomKind_ILOM, TestBoxData.ksLomKind_ELOM ]:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoLom += [ WuiLinkBase('(ssh)', 'ssh://%s' % (oEntry.ipLom,), fBracketed = False) ];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoLom += [ WuiRawHtml('<br>'), '%s' % (oEntry.ipLom,) ];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # State and Last seen.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oDelta = oEntry.tsCurrent - oEntry.oStatus.tsUpdated;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oDelta.days <= 0 and oDelta.seconds <= 15*60: # 15 mins and we consider you dead.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oSeen = WuiSpanText('tmspan-online', u'%s\u00a0s\u00a0ago' % (oDelta.days * 24 * 3600 + oDelta.seconds,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oSeen = WuiSpanText('tmspan-offline', u'%s' % (self.formatTsShort(oEntry.oStatus.tsUpdated),));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oState = WuiTmLink(oEntry.oStatus.enmState, WuiMain.ksScriptName,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { WuiMain.ksParamAction: WuiMain.ksActionTestResultDetails,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TestSetData.ksParam_idTestSet: oEntry.oStatus.idTestSet, },
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Group link.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oGroup = self._dSchedGroups.get(oEntry.idSchedGroup);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oGroupLink = WuiTmLink(oGroup.sName if oGroup is not None else str(oEntry.idSchedGroup),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { WuiAdmin.ksParamAction: WuiAdmin.ksActionSchedGroupEdit,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync SchedGroupData.ksParam_idSchedGroup: oEntry.idSchedGroup, },
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Reformat the OS version to take less space.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oEntry.sOs is not None and oEntry.sOsVersion is not None and oEntry.sCpuArch:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync and oEntry.sOs in [ 'linux', 'solaris', 'darwin', ]:
f5f22d30238f9adf5a42a510ff1683bca461600cvboxsync if oEntry.sOs == 'linux' or oEntry.sOs == 'darwin':
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sVer2 = sVer2.replace('Red Hat Enterprise Linux Server', 'RHEL');
3f8c00daa9a41eeb005842cd21f9edbe0ed61193vboxsync sVer2 = sVer2.replace('Oracle Linux Server', 'OL');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiSpanText('tmspan-osarch', u'%s.%s' % (oEntry.sOs, oEntry.sCpuArch,)),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiSpanText('tmspan-osver1', sVer1.replace('-', u'\u2011'),),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if sVer2 is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoOs += [ WuiRawHtml('<br>'), WuiSpanText('tmspan-osver2', sVer2.replace('-', u'\u2011')), ];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Format the CPU revision.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oEntry.lCpuRevision is not None and oEntry.sCpuVendor is not None and oEntry.sCpuName is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync u'%s (fam:%xh\u00a0m:%xh\u00a0s:%xh)'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (oEntry.sCpuVendor, oEntry.getCpuFamily(), oEntry.getCpuModel(), oEntry.getCpuStepping(),),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Stuff cpu vendor and cpu/box features into one field.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oEntry.fCpuHwVirt is True: asFeatures.append(u'HW\u2011Virt');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oEntry.fCpuNestedPaging is True: asFeatures.append(u'Nested\u2011Paging');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oEntry.fCpu64BitGuest is True: asFeatures.append(u'64\u2011bit\u2011Guest');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oEntry.fChipsetIoMmu is True: asFeatures.append(u'I/O\u2011MMU');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sFeatures = u' '.join(asFeatures) if len(asFeatures) > 0 else u'';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Collection applicable actions.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxDetails,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiAdmin.ksParamEffectiveDate: self._tsEffectiveDate, } ),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxEdit,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TestBoxData.ksParam_idTestBox: oEntry.idTestBox, } ),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxRemovePost,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sConfirm = 'Are you sure that you want to remove %s (%s)?' % (oEntry.sName, oEntry.ip) ),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oEntry.sOs not in [ 'win', 'os2', ] and oEntry.ip is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoActions.append(WuiLinkBase('ssh', 'ssh://vbox@%s' % (oEntry.ip,),));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return [ self._getCheckBoxColumn(iEntry, oEntry.idTestBox),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync [ WuiSpanText('tmspan-name', oEntry.sName), WuiRawHtml('<br>'), '%s' % (oEntry.ip,),],
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oEntry.cCpus if oEntry.cCpus is not None else 'N/A',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync utils.formatNumberNbsp(oEntry.cMbMemory) + u'\u00a0MB' if oEntry.cMbMemory is not None else 'N/A',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync utils.formatNumberNbsp(oEntry.cMbScratch) + u'\u00a0MB' if oEntry.cMbScratch is not None else 'N/A',