VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testmanager/webui/wuiadmintestbox.py@ 98103

Last change on this file since 98103 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.0 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: wuiadmintestbox.py 98103 2023-01-17 14:15:46Z vboxsync $
3
4"""
5Test Manager WUI - TestBox.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2023 Oracle and/or its affiliates.
11
12This file is part of VirtualBox base platform packages, as
13available from https://www.virtualbox.org.
14
15This program is free software; you can redistribute it and/or
16modify it under the terms of the GNU General Public License
17as published by the Free Software Foundation, in version 3 of the
18License.
19
20This program is distributed in the hope that it will be useful, but
21WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23General Public License for more details.
24
25You should have received a copy of the GNU General Public License
26along with this program; if not, see <https://www.gnu.org/licenses>.
27
28The contents of this file may alternatively be used under the terms
29of the Common Development and Distribution License Version 1.0
30(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
31in the VirtualBox distribution, in which case the provisions of the
32CDDL are applicable instead of those of the GPL.
33
34You may elect to license modified versions of this file under the
35terms and conditions of either the GPL or the CDDL or both.
36
37SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
38"""
39__version__ = "$Revision: 98103 $"
40
41
42# Standard python imports.
43import socket;
44
45# Validation Kit imports.
46from common import utils, webutils;
47from testmanager.webui.wuicontentbase import WuiContentBase, WuiListContentWithActionBase, WuiFormContentBase, WuiLinkBase, \
48 WuiSvnLink, WuiTmLink, WuiSpanText, WuiRawHtml;
49from testmanager.core.db import TMDatabaseConnection;
50from testmanager.core.schedgroup import SchedGroupLogic, SchedGroupData;
51from testmanager.core.testbox import TestBoxData, TestBoxDataEx, TestBoxLogic;
52from testmanager.core.testset import TestSetData;
53from testmanager.core.db import isDbTimestampInfinity;
54
55
56
57class WuiTestBoxDetailsLinkById(WuiTmLink):
58 """ Test box details link by ID. """
59
60 def __init__(self, idTestBox, sName = WuiContentBase.ksShortDetailsLink, fBracketed = False, tsNow = None, sTitle = None):
61 from testmanager.webui.wuiadmin import WuiAdmin;
62 dParams = {
63 WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxDetails,
64 TestBoxData.ksParam_idTestBox: idTestBox,
65 };
66 if tsNow is not None:
67 dParams[WuiAdmin.ksParamEffectiveDate] = tsNow; ## ??
68 WuiTmLink.__init__(self, sName, WuiAdmin.ksScriptName, dParams, fBracketed = fBracketed, sTitle = sTitle);
69 self.idTestBox = idTestBox;
70
71
72class WuiTestBoxDetailsLink(WuiTestBoxDetailsLinkById):
73 """ Test box details link by TestBoxData instance. """
74
75 def __init__(self, oTestBox, sName = None, fBracketed = False, tsNow = None): # (TestBoxData, str, bool, Any) -> None
76 WuiTestBoxDetailsLinkById.__init__(self, oTestBox.idTestBox,
77 sName if sName else oTestBox.sName,
78 fBracketed = fBracketed,
79 tsNow = tsNow,
80 sTitle = self.formatTitleText(oTestBox));
81 self.oTestBox = oTestBox;
82
83 @staticmethod
84 def formatTitleText(oTestBox): # (TestBoxData) -> str
85 """
86 Formats the title text for a TestBoxData object.
87 """
88
89 # Note! Somewhat similar code is found in testresults.py
90
91 #
92 # Collect field/value tuples.
93 #
94 aasTestBoxTitle = [
95 (u'Identifier:', '#%u' % (oTestBox.idTestBox,),),
96 (u'Name:', oTestBox.sName,),
97 ];
98 if oTestBox.sCpuVendor:
99 aasTestBoxTitle.append((u'CPU\u00a0vendor:', oTestBox.sCpuVendor, ));
100 if oTestBox.sCpuName:
101 aasTestBoxTitle.append((u'CPU\u00a0name:', u'\u00a0'.join(oTestBox.sCpuName.split()),));
102 if oTestBox.cCpus:
103 aasTestBoxTitle.append((u'CPU\u00a0threads:', u'%s' % ( oTestBox.cCpus, ),));
104
105 asFeatures = [];
106 if oTestBox.fCpuHwVirt is True:
107 if oTestBox.sCpuVendor is None:
108 asFeatures.append(u'HW\u2011Virt');
109 elif oTestBox.sCpuVendor in ['AuthenticAMD',]:
110 asFeatures.append(u'HW\u2011Virt(AMD\u2011V)');
111 else:
112 asFeatures.append(u'HW\u2011Virt(VT\u2011x)');
113 if oTestBox.fCpuNestedPaging is True: asFeatures.append(u'Nested\u2011Paging');
114 if oTestBox.fCpu64BitGuest is True: asFeatures.append(u'64\u2011bit\u2011Guest');
115 if oTestBox.fChipsetIoMmu is True: asFeatures.append(u'I/O\u2011MMU');
116 aasTestBoxTitle.append((u'CPU\u00a0features:', u',\u00a0'.join(asFeatures),));
117
118 if oTestBox.cMbMemory:
119 aasTestBoxTitle.append((u'System\u00a0RAM:', u'%s MiB' % ( oTestBox.cMbMemory, ),));
120 if oTestBox.sOs:
121 aasTestBoxTitle.append((u'OS:', oTestBox.sOs, ));
122 if oTestBox.sCpuArch:
123 aasTestBoxTitle.append((u'OS\u00a0arch:', oTestBox.sCpuArch,));
124 if oTestBox.sOsVersion:
125 aasTestBoxTitle.append((u'OS\u00a0version:', u'\u00a0'.join(oTestBox.sOsVersion.split()),));
126 if oTestBox.ip:
127 aasTestBoxTitle.append((u'IP\u00a0address:', u'%s' % ( oTestBox.ip, ),));
128
129 #
130 # Do a guestimation of the max field name width and pad short
131 # names when constructing the title text lines.
132 #
133 cchMaxWidth = 0;
134 for sEntry, _ in aasTestBoxTitle:
135 cchMaxWidth = max(WuiTestBoxDetailsLink.estimateStringWidth(sEntry), cchMaxWidth);
136 asTestBoxTitle = [];
137 for sEntry, sValue in aasTestBoxTitle:
138 asTestBoxTitle.append(u'%s%s\t\t%s'
139 % (sEntry, WuiTestBoxDetailsLink.getStringWidthPadding(sEntry, cchMaxWidth), sValue));
140
141 return u'\n'.join(asTestBoxTitle);
142
143
144class WuiTestBoxDetailsLinkShort(WuiTestBoxDetailsLink):
145 """ Test box details link by TestBoxData instance, but with ksShortDetailsLink as default name. """
146
147 def __init__(self, oTestBox, sName = WuiContentBase.ksShortDetailsLink, fBracketed = False,
148 tsNow = None): # (TestBoxData, str, bool, Any) -> None
149 WuiTestBoxDetailsLink.__init__(self, oTestBox, sName = sName, fBracketed = fBracketed, tsNow = tsNow);
150
151
152class WuiTestBox(WuiFormContentBase):
153 """
154 WUI TestBox Form Content Generator.
155 """
156
157 def __init__(self, oData, sMode, oDisp):
158 if sMode == WuiFormContentBase.ksMode_Add:
159 sTitle = 'Create TextBox';
160 if oData.uuidSystem is not None and len(oData.uuidSystem) > 10:
161 sTitle += ' - ' + oData.uuidSystem;
162 elif sMode == WuiFormContentBase.ksMode_Edit:
163 sTitle = 'Edit TestBox - %s (#%s)' % (oData.sName, oData.idTestBox);
164 else:
165 assert sMode == WuiFormContentBase.ksMode_Show;
166 sTitle = 'TestBox - %s (#%s)' % (oData.sName, oData.idTestBox);
167 WuiFormContentBase.__init__(self, oData, sMode, 'TestBox', oDisp, sTitle);
168
169 # Try enter sName as hostname (no domain) when creating the testbox.
170 if sMode == WuiFormContentBase.ksMode_Add \
171 and self._oData.sName in [None, ''] \
172 and self._oData.ip not in [None, '']:
173 try:
174 (self._oData.sName, _, _) = socket.gethostbyaddr(self._oData.ip);
175 except:
176 pass;
177 offDot = self._oData.sName.find('.');
178 if offDot > 0:
179 self._oData.sName = self._oData.sName[:offDot];
180
181
182 def _populateForm(self, oForm, oData):
183 oForm.addIntRO( TestBoxData.ksParam_idTestBox, oData.idTestBox, 'TestBox ID');
184 oForm.addIntRO( TestBoxData.ksParam_idGenTestBox, oData.idGenTestBox, 'TestBox generation ID');
185 oForm.addTimestampRO(TestBoxData.ksParam_tsEffective, oData.tsEffective, 'Last changed');
186 oForm.addTimestampRO(TestBoxData.ksParam_tsExpire, oData.tsExpire, 'Expires (excl)');
187 oForm.addIntRO( TestBoxData.ksParam_uidAuthor, oData.uidAuthor, 'Changed by UID');
188
189 oForm.addText( TestBoxData.ksParam_ip, oData.ip, 'TestBox IP Address'); ## make read only??
190 oForm.addUuid( TestBoxData.ksParam_uuidSystem, oData.uuidSystem, 'TestBox System/Firmware UUID');
191 oForm.addText( TestBoxData.ksParam_sName, oData.sName, 'TestBox Name');
192 oForm.addText( TestBoxData.ksParam_sDescription, oData.sDescription, 'TestBox Description');
193 oForm.addCheckBox( TestBoxData.ksParam_fEnabled, oData.fEnabled, 'Enabled');
194 oForm.addComboBox( TestBoxData.ksParam_enmLomKind, oData.enmLomKind, 'Lights-out-management',
195 TestBoxData.kaoLomKindDescs);
196 oForm.addText( TestBoxData.ksParam_ipLom, oData.ipLom, 'Lights-out-management IP Address');
197 oForm.addInt( TestBoxData.ksParam_pctScaleTimeout, oData.pctScaleTimeout, 'Timeout scale factor (%)');
198
199 oForm.addListOfSchedGroupsForTestBox(TestBoxDataEx.ksParam_aoInSchedGroups,
200 oData.aoInSchedGroups,
201 SchedGroupLogic(TMDatabaseConnection()).fetchOrderedByName(),
202 'Scheduling Group', oData.idTestBox);
203 # Command, comment and submit button.
204 if self._sMode == WuiFormContentBase.ksMode_Edit:
205 oForm.addComboBox(TestBoxData.ksParam_enmPendingCmd, oData.enmPendingCmd, 'Pending command',
206 TestBoxData.kaoTestBoxCmdDescs);
207 else:
208 oForm.addComboBoxRO(TestBoxData.ksParam_enmPendingCmd, oData.enmPendingCmd, 'Pending command',
209 TestBoxData.kaoTestBoxCmdDescs);
210 oForm.addMultilineText(TestBoxData.ksParam_sComment, oData.sComment, 'Comment');
211 if self._sMode != WuiFormContentBase.ksMode_Show:
212 oForm.addSubmit('Create TestBox' if self._sMode == WuiFormContentBase.ksMode_Add else 'Change TestBox');
213
214 return True;
215
216
217 def _generatePostFormContent(self, oData):
218 from testmanager.webui.wuihlpform import WuiHlpForm;
219
220 oForm = WuiHlpForm('testbox-machine-settable', '', fReadOnly = True);
221 oForm.addTextRO( TestBoxData.ksParam_sOs, oData.sOs, 'TestBox OS');
222 oForm.addTextRO( TestBoxData.ksParam_sOsVersion, oData.sOsVersion, 'TestBox OS version');
223 oForm.addTextRO( TestBoxData.ksParam_sCpuArch, oData.sCpuArch, 'TestBox OS kernel architecture');
224 oForm.addTextRO( TestBoxData.ksParam_sCpuVendor, oData.sCpuVendor, 'TestBox CPU vendor');
225 oForm.addTextRO( TestBoxData.ksParam_sCpuName, oData.sCpuName, 'TestBox CPU name');
226 if oData.lCpuRevision:
227 oForm.addTextRO( TestBoxData.ksParam_lCpuRevision, '%#x' % (oData.lCpuRevision,), 'TestBox CPU revision',
228 sPostHtml = ' (family=%#x model=%#x stepping=%#x)'
229 % (oData.getCpuFamily(), oData.getCpuModel(), oData.getCpuStepping(),),
230 sSubClass = 'long');
231 else:
232 oForm.addLongRO( TestBoxData.ksParam_lCpuRevision, oData.lCpuRevision, 'TestBox CPU revision');
233 oForm.addIntRO( TestBoxData.ksParam_cCpus, oData.cCpus, 'Number of CPUs, cores and threads');
234 oForm.addCheckBoxRO( TestBoxData.ksParam_fCpuHwVirt, oData.fCpuHwVirt, 'VT-x or AMD-V supported');
235 oForm.addCheckBoxRO( TestBoxData.ksParam_fCpuNestedPaging, oData.fCpuNestedPaging, 'Nested paging supported');
236 oForm.addCheckBoxRO( TestBoxData.ksParam_fCpu64BitGuest, oData.fCpu64BitGuest, '64-bit guest supported');
237 oForm.addCheckBoxRO( TestBoxData.ksParam_fChipsetIoMmu, oData.fChipsetIoMmu, 'I/O MMU supported');
238 oForm.addMultilineTextRO(TestBoxData.ksParam_sReport, oData.sReport, 'Hardware/software report');
239 oForm.addLongRO( TestBoxData.ksParam_cMbMemory, oData.cMbMemory, 'Installed RAM size (MB)');
240 oForm.addLongRO( TestBoxData.ksParam_cMbScratch, oData.cMbScratch, 'Available scratch space (MB)');
241 oForm.addIntRO( TestBoxData.ksParam_iTestBoxScriptRev, oData.iTestBoxScriptRev,
242 'TestBox Script SVN revision');
243 sHexVer = oData.formatPythonVersion();
244 oForm.addIntRO( TestBoxData.ksParam_iPythonHexVersion, oData.iPythonHexVersion,
245 'Python version (hex)', sPostHtml = webutils.escapeElem(sHexVer));
246 return [('Machine Only Settables', oForm.finalize()),];
247
248
249
250class WuiTestBoxList(WuiListContentWithActionBase):
251 """
252 WUI TestBox List Content Generator.
253 """
254
255 ## Descriptors for the combo box.
256 kasTestBoxActionDescs = \
257 [ \
258 [ 'none', 'Select an action...', '' ],
259 [ 'enable', 'Enable', '' ],
260 [ 'disable', 'Disable', '' ],
261 TestBoxData.kaoTestBoxCmdDescs[1],
262 TestBoxData.kaoTestBoxCmdDescs[2],
263 TestBoxData.kaoTestBoxCmdDescs[3],
264 TestBoxData.kaoTestBoxCmdDescs[4],
265 TestBoxData.kaoTestBoxCmdDescs[5],
266 ];
267
268 ## Boxes which doesn't report in for more than 15 min are considered dead.
269 kcSecMaxStatusDeltaAlive = 15*60
270
271 def __init__(self, aoEntries, iPage, cItemsPerPage, tsEffective, fnDPrint, oDisp, aiSelectedSortColumns = None):
272 # type: (list[TestBoxDataForListing], int, int, datetime.datetime, ignore, WuiAdmin) -> None
273 WuiListContentWithActionBase.__init__(self, aoEntries, iPage, cItemsPerPage, tsEffective,
274 sTitle = 'TestBoxes', sId = 'users', fnDPrint = fnDPrint, oDisp = oDisp,
275 aiSelectedSortColumns = aiSelectedSortColumns);
276 self._asColumnHeaders.extend([ 'Name', 'LOM', 'Status', 'Cmd',
277 'Note', 'Script', 'Python', 'Group',
278 'OS', 'CPU', 'Features', 'CPUs', 'RAM', 'Scratch',
279 'Actions' ]);
280 self._asColumnAttribs.extend([ 'align="center"', 'align="center"', 'align="center"', 'align="center"'
281 'align="center"', 'align="center"', 'align="center"', 'align="center"',
282 '', '', '', 'align="left"', 'align="right"', 'align="right"', 'align="right"',
283 'align="center"' ]);
284 self._aaiColumnSorting.extend([
285 (TestBoxLogic.kiSortColumn_sName,),
286 None, # LOM
287 (-TestBoxLogic.kiSortColumn_fEnabled, TestBoxLogic.kiSortColumn_enmState, -TestBoxLogic.kiSortColumn_tsUpdated,),
288 (TestBoxLogic.kiSortColumn_enmPendingCmd,),
289 None, # Note
290 (TestBoxLogic.kiSortColumn_iTestBoxScriptRev,),
291 (TestBoxLogic.kiSortColumn_iPythonHexVersion,),
292 None, # Group
293 (TestBoxLogic.kiSortColumn_sOs, TestBoxLogic.kiSortColumn_sOsVersion, TestBoxLogic.kiSortColumn_sCpuArch,),
294 (TestBoxLogic.kiSortColumn_sCpuVendor, TestBoxLogic.kiSortColumn_lCpuRevision,),
295 (TestBoxLogic.kiSortColumn_fCpuNestedPaging,),
296 (TestBoxLogic.kiSortColumn_cCpus,),
297 (TestBoxLogic.kiSortColumn_cMbMemory,),
298 (TestBoxLogic.kiSortColumn_cMbScratch,),
299 None, # Actions
300 ]);
301 assert len(self._aaiColumnSorting) == len(self._asColumnHeaders);
302 self._aoActions = list(self.kasTestBoxActionDescs);
303 self._sAction = oDisp.ksActionTestBoxListPost;
304 self._sCheckboxName = TestBoxData.ksParam_idTestBox;
305
306 def show(self, fShowNavigation = True):
307 """ Adds some stats at the bottom of the page """
308 (sTitle, sBody) = super(WuiTestBoxList, self).show(fShowNavigation);
309
310 # Count boxes in interesting states.
311 if self._aoEntries:
312 cActive = 0;
313 cDead = 0;
314 for oTestBox in self._aoEntries:
315 if oTestBox.oStatus is not None:
316 oDelta = oTestBox.tsCurrent - oTestBox.oStatus.tsUpdated;
317 if oDelta.days <= 0 and oDelta.seconds <= self.kcSecMaxStatusDeltaAlive:
318 if oTestBox.fEnabled:
319 cActive += 1;
320 else:
321 cDead += 1;
322 else:
323 cDead += 1;
324 sBody += '<div id="testboxsummary"><p>\n' \
325 '%s testboxes of which %s are active and %s dead' \
326 '</p></div>\n' \
327 % (len(self._aoEntries), cActive, cDead,)
328 return (sTitle, sBody);
329
330 def _formatListEntry(self, iEntry): # pylint: disable=too-many-locals
331 from testmanager.webui.wuiadmin import WuiAdmin;
332 oEntry = self._aoEntries[iEntry];
333
334 # Lights outs managment.
335 if oEntry.enmLomKind == TestBoxData.ksLomKind_ILOM:
336 aoLom = [ WuiLinkBase('ILOM', 'https://%s/' % (oEntry.ipLom,), fBracketed = False), ];
337 elif oEntry.enmLomKind == TestBoxData.ksLomKind_ELOM:
338 aoLom = [ WuiLinkBase('ELOM', 'http://%s/' % (oEntry.ipLom,), fBracketed = False), ];
339 elif oEntry.enmLomKind == TestBoxData.ksLomKind_AppleXserveLom:
340 aoLom = [ 'Apple LOM' ];
341 elif oEntry.enmLomKind == TestBoxData.ksLomKind_None:
342 aoLom = [ 'none' ];
343 else:
344 aoLom = [ 'Unexpected enmLomKind value "%s"' % (oEntry.enmLomKind,) ];
345 if oEntry.ipLom is not None:
346 if oEntry.enmLomKind in [ TestBoxData.ksLomKind_ILOM, TestBoxData.ksLomKind_ELOM ]:
347 aoLom += [ WuiLinkBase('(ssh)', 'ssh://%s' % (oEntry.ipLom,), fBracketed = False) ];
348 aoLom += [ WuiRawHtml('<br>'), '%s' % (oEntry.ipLom,) ];
349
350 # State and Last seen.
351 if oEntry.oStatus is None:
352 oSeen = WuiSpanText('tmspan-offline', 'Never');
353 oState = '';
354 else:
355 oDelta = oEntry.tsCurrent - oEntry.oStatus.tsUpdated;
356 if oDelta.days <= 0 and oDelta.seconds <= self.kcSecMaxStatusDeltaAlive:
357 oSeen = WuiSpanText('tmspan-online', u'%s\u00a0s\u00a0ago' % (oDelta.days * 24 * 3600 + oDelta.seconds,));
358 else:
359 oSeen = WuiSpanText('tmspan-offline', u'%s' % (self.formatTsShort(oEntry.oStatus.tsUpdated),));
360
361 if oEntry.oStatus.idTestSet is None:
362 oState = str(oEntry.oStatus.enmState);
363 else:
364 from testmanager.webui.wuimain import WuiMain;
365 oState = WuiTmLink(oEntry.oStatus.enmState, WuiMain.ksScriptName, # pylint: disable=redefined-variable-type
366 { WuiMain.ksParamAction: WuiMain.ksActionTestResultDetails,
367 TestSetData.ksParam_idTestSet: oEntry.oStatus.idTestSet, },
368 sTitle = '#%u' % (oEntry.oStatus.idTestSet,),
369 fBracketed = False);
370 # Comment
371 oComment = self._formatCommentCell(oEntry.sComment);
372
373 # Group links.
374 aoGroups = [];
375 for oInGroup in oEntry.aoInSchedGroups:
376 oSchedGroup = oInGroup.oSchedGroup;
377 aoGroups.append(WuiTmLink(oSchedGroup.sName, WuiAdmin.ksScriptName,
378 { WuiAdmin.ksParamAction: WuiAdmin.ksActionSchedGroupEdit,
379 SchedGroupData.ksParam_idSchedGroup: oSchedGroup.idSchedGroup, },
380 sTitle = '#%u' % (oSchedGroup.idSchedGroup,),
381 fBracketed = len(oEntry.aoInSchedGroups) > 1));
382
383 # Reformat the OS version to take less space.
384 aoOs = [ 'N/A' ];
385 if oEntry.sOs is not None and oEntry.sOsVersion is not None and oEntry.sCpuArch:
386 sOsVersion = oEntry.sOsVersion;
387 if sOsVersion[0] not in [ 'v', 'V', 'r', 'R'] \
388 and sOsVersion[0].isdigit() \
389 and sOsVersion.find('.') in range(4) \
390 and oEntry.sOs in [ 'linux', 'solaris', 'darwin', ]:
391 sOsVersion = 'v' + sOsVersion;
392
393 sVer1 = sOsVersion;
394 sVer2 = None;
395 if oEntry.sOs in ('linux', 'darwin'):
396 iSep = sOsVersion.find(' / ');
397 if iSep > 0:
398 sVer1 = sOsVersion[:iSep].strip();
399 sVer2 = sOsVersion[iSep + 3:].strip();
400 sVer2 = sVer2.replace('Red Hat Enterprise Linux Server', 'RHEL');
401 sVer2 = sVer2.replace('Oracle Linux Server', 'OL');
402 elif oEntry.sOs == 'solaris':
403 iSep = sOsVersion.find(' (');
404 if iSep > 0 and sOsVersion[-1] == ')':
405 sVer1 = sOsVersion[:iSep].strip();
406 sVer2 = sOsVersion[iSep + 2:-1].strip();
407 elif oEntry.sOs == 'win':
408 iSep = sOsVersion.find('build');
409 if iSep > 0:
410 sVer1 = sOsVersion[:iSep].strip();
411 sVer2 = 'B' + sOsVersion[iSep + 1:].strip();
412 aoOs = [
413 WuiSpanText('tmspan-osarch', u'%s.%s' % (oEntry.sOs, oEntry.sCpuArch,)),
414 WuiSpanText('tmspan-osver1', sVer1.replace('-', u'\u2011'),),
415 ];
416 if sVer2 is not None:
417 aoOs += [ WuiRawHtml('<br>'), WuiSpanText('tmspan-osver2', sVer2.replace('-', u'\u2011')), ];
418
419 # Format the CPU revision.
420 oCpu = None;
421 if oEntry.lCpuRevision is not None and oEntry.sCpuVendor is not None and oEntry.sCpuName is not None:
422 oCpu = [
423 u'%s (fam:%xh\u00a0m:%xh\u00a0s:%xh)'
424 % (oEntry.sCpuVendor, oEntry.getCpuFamily(), oEntry.getCpuModel(), oEntry.getCpuStepping(),),
425 WuiRawHtml('<br>'),
426 oEntry.sCpuName,
427 ];
428 else:
429 oCpu = [];
430 if oEntry.sCpuVendor is not None:
431 oCpu.append(oEntry.sCpuVendor);
432 if oEntry.lCpuRevision is not None:
433 oCpu.append('%#x' % (oEntry.lCpuRevision,));
434 if oEntry.sCpuName is not None:
435 oCpu.append(oEntry.sCpuName);
436
437 # Stuff cpu vendor and cpu/box features into one field.
438 asFeatures = []
439 if oEntry.fCpuHwVirt is True: asFeatures.append(u'HW\u2011Virt');
440 if oEntry.fCpuNestedPaging is True: asFeatures.append(u'Nested\u2011Paging');
441 if oEntry.fCpu64BitGuest is True: asFeatures.append(u'64\u2011bit\u2011Guest');
442 if oEntry.fChipsetIoMmu is True: asFeatures.append(u'I/O\u2011MMU');
443 sFeatures = u' '.join(asFeatures) if asFeatures else u'';
444
445 # Collection applicable actions.
446 aoActions = [
447 WuiTmLink('Details', WuiAdmin.ksScriptName,
448 { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxDetails,
449 TestBoxData.ksParam_idTestBox: oEntry.idTestBox,
450 WuiAdmin.ksParamEffectiveDate: self._tsEffectiveDate, } ),
451 ]
452
453 if self._oDisp is None or not self._oDisp.isReadOnlyUser():
454 if isDbTimestampInfinity(oEntry.tsExpire):
455 aoActions += [
456 WuiTmLink('Edit', WuiAdmin.ksScriptName,
457 { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxEdit,
458 TestBoxData.ksParam_idTestBox: oEntry.idTestBox, } ),
459 WuiTmLink('Remove', WuiAdmin.ksScriptName,
460 { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxRemovePost,
461 TestBoxData.ksParam_idTestBox: oEntry.idTestBox },
462 sConfirm = 'Are you sure that you want to remove %s (%s)?' % (oEntry.sName, oEntry.ip) ),
463 ]
464
465 if oEntry.sOs not in [ 'win', 'os2', ] and oEntry.ip is not None:
466 aoActions.append(WuiLinkBase('ssh', 'ssh://vbox@%s' % (oEntry.ip,),));
467
468 return [ self._getCheckBoxColumn(iEntry, oEntry.idTestBox),
469 [ WuiSpanText('tmspan-name', oEntry.sName), WuiRawHtml('<br>'), '%s' % (oEntry.ip,),],
470 aoLom,
471 [
472 '' if oEntry.fEnabled else 'disabled / ',
473 oState,
474 WuiRawHtml('<br>'),
475 oSeen,
476 ],
477 oEntry.enmPendingCmd,
478 oComment,
479 WuiSvnLink(oEntry.iTestBoxScriptRev),
480 oEntry.formatPythonVersion(),
481 aoGroups,
482 aoOs,
483 oCpu,
484 sFeatures,
485 oEntry.cCpus if oEntry.cCpus is not None else 'N/A',
486 utils.formatNumberNbsp(oEntry.cMbMemory) + u'\u00a0MB' if oEntry.cMbMemory is not None else 'N/A',
487 utils.formatNumberNbsp(oEntry.cMbScratch) + u'\u00a0MB' if oEntry.cMbScratch is not None else 'N/A',
488 aoActions,
489 ];
490
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette