VirtualBox

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

Last change on this file since 88745 was 83403, checked in by vboxsync, 5 years ago

TestManager/webui: Better/generic testbox links.

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