VirtualBox

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

Last change on this file since 65132 was 64986, checked in by vboxsync, 8 years ago

testmanager/webui: started on test result filtering.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.5 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: wuiadmintestbox.py 64986 2016-12-21 14:36:33Z vboxsync $
3
4"""
5Test Manager WUI - TestBox.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2016 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: 64986 $"
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;
42from testmanager.core.testset import TestSetData;
43from testmanager.core.db import isDbTimestampInfinity;
44
45
46
47class WuiTestBoxDetailsLink(WuiTmLink):
48 """ Test box details link by ID. """
49
50 def __init__(self, idTestBox, sName = WuiContentBase.ksShortDetailsLink, fBracketed = False, tsNow = 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);
59 self.idTestBox = idTestBox;
60
61
62
63class WuiTestBox(WuiFormContentBase):
64 """
65 WUI TestBox Form Content Generator.
66 """
67
68 def __init__(self, oData, sMode, oDisp):
69 if sMode == WuiFormContentBase.ksMode_Add:
70 sTitle = 'Create TextBox';
71 if oData.uuidSystem is not None and len(oData.uuidSystem) > 10:
72 sTitle += ' - ' + oData.uuidSystem;
73 elif sMode == WuiFormContentBase.ksMode_Edit:
74 sTitle = 'Edit TestBox - %s (#%s)' % (oData.sName, oData.idTestBox);
75 else:
76 assert sMode == WuiFormContentBase.ksMode_Show;
77 sTitle = 'TestBox - %s (#%s)' % (oData.sName, oData.idTestBox);
78 WuiFormContentBase.__init__(self, oData, sMode, 'TestBox', oDisp, sTitle);
79
80 # Try enter sName as hostname (no domain) when creating the testbox.
81 if sMode == WuiFormContentBase.ksMode_Add \
82 and self._oData.sName in [None, ''] \
83 and self._oData.ip not in [None, '']:
84 try:
85 (self._oData.sName, _, _) = socket.gethostbyaddr(self._oData.ip);
86 except:
87 pass;
88 offDot = self._oData.sName.find('.');
89 if offDot > 0:
90 self._oData.sName = self._oData.sName[:offDot];
91
92
93 def _populateForm(self, oForm, oData):
94 oForm.addIntRO( TestBoxData.ksParam_idTestBox, oData.idTestBox, 'TestBox ID');
95 oForm.addIntRO( TestBoxData.ksParam_idGenTestBox, oData.idGenTestBox, 'TestBox generation ID');
96 oForm.addTimestampRO(TestBoxData.ksParam_tsEffective, oData.tsEffective, 'Last changed');
97 oForm.addTimestampRO(TestBoxData.ksParam_tsExpire, oData.tsExpire, 'Expires (excl)');
98 oForm.addIntRO( TestBoxData.ksParam_uidAuthor, oData.uidAuthor, 'Changed by UID');
99
100 oForm.addText( TestBoxData.ksParam_ip, oData.ip, 'TestBox IP Address'); ## make read only??
101 oForm.addUuid( TestBoxData.ksParam_uuidSystem, oData.uuidSystem, 'TestBox System/Firmware UUID');
102 oForm.addText( TestBoxData.ksParam_sName, oData.sName, 'TestBox Name');
103 oForm.addText( TestBoxData.ksParam_sDescription, oData.sDescription, 'TestBox Description');
104 oForm.addCheckBox( TestBoxData.ksParam_fEnabled, oData.fEnabled, 'Enabled');
105 oForm.addComboBox( TestBoxData.ksParam_enmLomKind, oData.enmLomKind, 'Lights-out-management',
106 TestBoxData.kaoLomKindDescs);
107 oForm.addText( TestBoxData.ksParam_ipLom, oData.ipLom, 'Lights-out-management IP Address');
108 oForm.addInt( TestBoxData.ksParam_pctScaleTimeout, oData.pctScaleTimeout, 'Timeout scale factor (%)');
109
110 oForm.addListOfSchedGroupsForTestBox(TestBoxDataEx.ksParam_aoInSchedGroups,
111 oData.aoInSchedGroups,
112 SchedGroupLogic(TMDatabaseConnection()).fetchOrderedByName(),
113 'Scheduling Group');
114 # Command, comment and submit button.
115 if self._sMode == WuiFormContentBase.ksMode_Edit:
116 oForm.addComboBox(TestBoxData.ksParam_enmPendingCmd, oData.enmPendingCmd, 'Pending command',
117 TestBoxData.kaoTestBoxCmdDescs);
118 else:
119 oForm.addComboBoxRO(TestBoxData.ksParam_enmPendingCmd, oData.enmPendingCmd, 'Pending command',
120 TestBoxData.kaoTestBoxCmdDescs);
121 oForm.addMultilineText(TestBoxData.ksParam_sComment, oData.sComment, 'Comment');
122 if self._sMode != WuiFormContentBase.ksMode_Show:
123 oForm.addSubmit('Create TestBox' if self._sMode == WuiFormContentBase.ksMode_Add else 'Change TestBox');
124
125 return True;
126
127
128 def _generatePostFormContent(self, oData):
129 from testmanager.webui.wuihlpform import WuiHlpForm;
130
131 oForm = WuiHlpForm('testbox-machine-settable', '', fReadOnly = True);
132 oForm.addTextRO( TestBoxData.ksParam_sOs, oData.sOs, 'TestBox OS');
133 oForm.addTextRO( TestBoxData.ksParam_sOsVersion, oData.sOsVersion, 'TestBox OS version');
134 oForm.addTextRO( TestBoxData.ksParam_sCpuArch, oData.sCpuArch, 'TestBox OS kernel architecture');
135 oForm.addTextRO( TestBoxData.ksParam_sCpuVendor, oData.sCpuVendor, 'TestBox CPU vendor');
136 oForm.addTextRO( TestBoxData.ksParam_sCpuName, oData.sCpuName, 'TestBox CPU name');
137 if oData.lCpuRevision:
138 oForm.addTextRO( TestBoxData.ksParam_lCpuRevision, '%#x' % (oData.lCpuRevision,), 'TestBox CPU revision',
139 sPostHtml = ' (family=%#x model=%#x stepping=%#x)'
140 % (oData.getCpuFamily(), oData.getCpuModel(), oData.getCpuStepping(),),
141 sSubClass = 'long');
142 else:
143 oForm.addLongRO( TestBoxData.ksParam_lCpuRevision, oData.lCpuRevision, 'TestBox CPU revision');
144 oForm.addIntRO( TestBoxData.ksParam_cCpus, oData.cCpus, 'Number of CPUs, cores and threads');
145 oForm.addCheckBoxRO( TestBoxData.ksParam_fCpuHwVirt, oData.fCpuHwVirt, 'VT-x or AMD-V supported');
146 oForm.addCheckBoxRO( TestBoxData.ksParam_fCpuNestedPaging, oData.fCpuNestedPaging, 'Nested paging supported');
147 oForm.addCheckBoxRO( TestBoxData.ksParam_fCpu64BitGuest, oData.fCpu64BitGuest, '64-bit guest supported');
148 oForm.addCheckBoxRO( TestBoxData.ksParam_fChipsetIoMmu, oData.fChipsetIoMmu, 'I/O MMU supported');
149 oForm.addMultilineTextRO(TestBoxData.ksParam_sReport, oData.sReport, 'Hardware/software report');
150 oForm.addLongRO( TestBoxData.ksParam_cMbMemory, oData.cMbMemory, 'Installed RAM size (MB)');
151 oForm.addLongRO( TestBoxData.ksParam_cMbScratch, oData.cMbScratch, 'Available scratch space (MB)');
152 oForm.addIntRO( TestBoxData.ksParam_iTestBoxScriptRev, oData.iTestBoxScriptRev,
153 'TestBox Script SVN revision');
154 sHexVer = oData.formatPythonVersion();
155 oForm.addIntRO( TestBoxData.ksParam_iPythonHexVersion, oData.iPythonHexVersion,
156 'Python version (hex)', sPostHtml = webutils.escapeElem(sHexVer));
157 return [('Machine Only Settables', oForm.finalize()),];
158
159
160
161class WuiTestBoxList(WuiListContentWithActionBase):
162 """
163 WUI TestBox List Content Generator.
164 """
165
166 ## Descriptors for the combo box.
167 kasTestBoxActionDescs = \
168 [ \
169 [ 'none', 'Select an action...', '' ],
170 [ 'enable', 'Enable', '' ],
171 [ 'disable', 'Disable', '' ],
172 TestBoxData.kaoTestBoxCmdDescs[1],
173 TestBoxData.kaoTestBoxCmdDescs[2],
174 TestBoxData.kaoTestBoxCmdDescs[3],
175 TestBoxData.kaoTestBoxCmdDescs[4],
176 TestBoxData.kaoTestBoxCmdDescs[5],
177 ];
178
179 ## Boxes which doesn't report in for more than 15 min are considered dead.
180 kcSecMaxStatusDeltaAlive = 15*60
181
182 def __init__(self, aoEntries, iPage, cItemsPerPage, tsEffective, fnDPrint, oDisp):
183 # type: (list[TestBoxDataForListing], int, int, datetime.datetime, ignore, WuiAdmin) -> None
184 WuiListContentWithActionBase.__init__(self, aoEntries, iPage, cItemsPerPage, tsEffective,
185 sTitle = 'TestBoxes', sId = 'users', fnDPrint = fnDPrint, oDisp = oDisp);
186 self._asColumnHeaders.extend([ 'Name', 'LOM', 'Status', 'Cmd',
187 'Note', 'Script', 'Python', 'Group',
188 'OS', 'CPU', 'Features', 'CPUs', 'RAM', 'Scratch',
189 'Actions' ]);
190 self._asColumnAttribs.extend([ 'align="center"', 'align="center"', 'align="center"', 'align="center"'
191 'align="center"', 'align="center"', 'align="center"', 'align="center"',
192 '', '', '', 'align="left"', 'align="right"', 'align="right"', 'align="right"',
193 'align="center"' ]);
194 self._aoActions = list(self.kasTestBoxActionDescs);
195 self._sAction = oDisp.ksActionTestBoxListPost;
196 self._sCheckboxName = TestBoxData.ksParam_idTestBox;
197
198 def show(self, fShowNavigation = True):
199 """ Adds some stats at the bottom of the page """
200 (sTitle, sBody) = super(WuiTestBoxList, self).show(fShowNavigation);
201
202 # Count boxes in interesting states.
203 if len(self._aoEntries) > 0:
204 cActive = 0;
205 cDead = 0;
206 for oTestBox in self._aoEntries:
207 if oTestBox.oStatus is not None:
208 oDelta = oTestBox.tsCurrent - oTestBox.oStatus.tsUpdated;
209 if oDelta.days <= 0 and oDelta.seconds <= self.kcSecMaxStatusDeltaAlive:
210 if oTestBox.fEnabled:
211 cActive += 1;
212 else:
213 cDead += 1;
214 else:
215 cDead += 1;
216 sBody += '<div id="testboxsummary"><p>\n' \
217 '%s testboxes of which %s are active and %s dead' \
218 '</p></div>\n' \
219 % (len(self._aoEntries), cActive, cDead,)
220 return (sTitle, sBody);
221
222 def _formatListEntry(self, iEntry): # pylint: disable=R0914
223 from testmanager.webui.wuiadmin import WuiAdmin;
224 oEntry = self._aoEntries[iEntry];
225
226 # Lights outs managment.
227 if oEntry.enmLomKind == TestBoxData.ksLomKind_ILOM:
228 aoLom = [ WuiLinkBase('ILOM', 'https://%s/' % (oEntry.ipLom,), fBracketed = False), ];
229 elif oEntry.enmLomKind == TestBoxData.ksLomKind_ELOM:
230 aoLom = [ WuiLinkBase('ELOM', 'http://%s/' % (oEntry.ipLom,), fBracketed = False), ];
231 elif oEntry.enmLomKind == TestBoxData.ksLomKind_AppleXserveLom:
232 aoLom = [ 'Apple LOM' ];
233 elif oEntry.enmLomKind == TestBoxData.ksLomKind_None:
234 aoLom = [ 'none' ];
235 else:
236 aoLom = [ 'Unexpected enmLomKind value "%s"' % (oEntry.enmLomKind,) ];
237 if oEntry.ipLom is not None:
238 if oEntry.enmLomKind in [ TestBoxData.ksLomKind_ILOM, TestBoxData.ksLomKind_ELOM ]:
239 aoLom += [ WuiLinkBase('(ssh)', 'ssh://%s' % (oEntry.ipLom,), fBracketed = False) ];
240 aoLom += [ WuiRawHtml('<br>'), '%s' % (oEntry.ipLom,) ];
241
242 # State and Last seen.
243 if oEntry.oStatus is None:
244 oSeen = WuiSpanText('tmspan-offline', 'Never');
245 oState = '';
246 else:
247 oDelta = oEntry.tsCurrent - oEntry.oStatus.tsUpdated;
248 if oDelta.days <= 0 and oDelta.seconds <= self.kcSecMaxStatusDeltaAlive:
249 oSeen = WuiSpanText('tmspan-online', u'%s\u00a0s\u00a0ago' % (oDelta.days * 24 * 3600 + oDelta.seconds,));
250 else:
251 oSeen = WuiSpanText('tmspan-offline', u'%s' % (self.formatTsShort(oEntry.oStatus.tsUpdated),));
252
253 if oEntry.oStatus.idTestSet is None:
254 oState = str(oEntry.oStatus.enmState);
255 else:
256 from testmanager.webui.wuimain import WuiMain;
257 oState = WuiTmLink(oEntry.oStatus.enmState, WuiMain.ksScriptName, # pylint: disable=R0204
258 { WuiMain.ksParamAction: WuiMain.ksActionTestResultDetails,
259 TestSetData.ksParam_idTestSet: oEntry.oStatus.idTestSet, },
260 sTitle = '#%u' % (oEntry.oStatus.idTestSet,),
261 fBracketed = False);
262 # Comment
263 oComment = self._formatCommentCell(oEntry.sComment);
264
265 # Group links.
266 aoGroups = [];
267 for oInGroup in oEntry.aoInSchedGroups:
268 oSchedGroup = oInGroup.oSchedGroup;
269 aoGroups.append(WuiTmLink(oSchedGroup.sName, WuiAdmin.ksScriptName,
270 { WuiAdmin.ksParamAction: WuiAdmin.ksActionSchedGroupEdit,
271 SchedGroupData.ksParam_idSchedGroup: oSchedGroup.idSchedGroup, },
272 sTitle = '#%u' % (oSchedGroup.idSchedGroup,),
273 fBracketed = len(oEntry.aoInSchedGroups) > 1));
274
275 # Reformat the OS version to take less space.
276 aoOs = [ 'N/A' ];
277 if oEntry.sOs is not None and oEntry.sOsVersion is not None and oEntry.sCpuArch:
278 sOsVersion = oEntry.sOsVersion;
279 if sOsVersion[0] not in [ 'v', 'V', 'r', 'R'] \
280 and sOsVersion[0].isdigit() \
281 and sOsVersion.find('.') in range(4) \
282 and oEntry.sOs in [ 'linux', 'solaris', 'darwin', ]:
283 sOsVersion = 'v' + sOsVersion;
284
285 sVer1 = sOsVersion;
286 sVer2 = None;
287 if oEntry.sOs == 'linux' or oEntry.sOs == 'darwin':
288 iSep = sOsVersion.find(' / ');
289 if iSep > 0:
290 sVer1 = sOsVersion[:iSep].strip();
291 sVer2 = sOsVersion[iSep + 3:].strip();
292 sVer2 = sVer2.replace('Red Hat Enterprise Linux Server', 'RHEL');
293 sVer2 = sVer2.replace('Oracle Linux Server', 'OL');
294 elif oEntry.sOs == 'solaris':
295 iSep = sOsVersion.find(' (');
296 if iSep > 0 and sOsVersion[-1] == ')':
297 sVer1 = sOsVersion[:iSep].strip();
298 sVer2 = sOsVersion[iSep + 2:-1].strip();
299 aoOs = [
300 WuiSpanText('tmspan-osarch', u'%s.%s' % (oEntry.sOs, oEntry.sCpuArch,)),
301 WuiSpanText('tmspan-osver1', sVer1.replace('-', u'\u2011'),),
302 ];
303 if sVer2 is not None:
304 aoOs += [ WuiRawHtml('<br>'), WuiSpanText('tmspan-osver2', sVer2.replace('-', u'\u2011')), ];
305
306 # Format the CPU revision.
307 oCpu = None;
308 if oEntry.lCpuRevision is not None and oEntry.sCpuVendor is not None and oEntry.sCpuName is not None:
309 oCpu = [
310 u'%s (fam:%xh\u00a0m:%xh\u00a0s:%xh)'
311 % (oEntry.sCpuVendor, oEntry.getCpuFamily(), oEntry.getCpuModel(), oEntry.getCpuStepping(),),
312 WuiRawHtml('<br>'),
313 oEntry.sCpuName,
314 ];
315 else:
316 oCpu = [];
317 if oEntry.sCpuVendor is not None:
318 oCpu.append(oEntry.sCpuVendor);
319 if oEntry.lCpuRevision is not None:
320 oCpu.append('%#x' % (oEntry.lCpuRevision,));
321 if oEntry.sCpuName is not None:
322 oCpu.append(oEntry.sCpuName);
323
324 # Stuff cpu vendor and cpu/box features into one field.
325 asFeatures = []
326 if oEntry.fCpuHwVirt is True: asFeatures.append(u'HW\u2011Virt');
327 if oEntry.fCpuNestedPaging is True: asFeatures.append(u'Nested\u2011Paging');
328 if oEntry.fCpu64BitGuest is True: asFeatures.append(u'64\u2011bit\u2011Guest');
329 if oEntry.fChipsetIoMmu is True: asFeatures.append(u'I/O\u2011MMU');
330 sFeatures = u' '.join(asFeatures) if len(asFeatures) > 0 else u'';
331
332 # Collection applicable actions.
333 aoActions = [
334 WuiTmLink('Details', WuiAdmin.ksScriptName,
335 { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxDetails,
336 TestBoxData.ksParam_idTestBox: oEntry.idTestBox,
337 WuiAdmin.ksParamEffectiveDate: self._tsEffectiveDate, } ),
338 ]
339
340 if isDbTimestampInfinity(oEntry.tsExpire):
341 aoActions += [
342 WuiTmLink('Edit', WuiAdmin.ksScriptName,
343 { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxEdit,
344 TestBoxData.ksParam_idTestBox: oEntry.idTestBox, } ),
345 WuiTmLink('Remove', WuiAdmin.ksScriptName,
346 { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxRemovePost,
347 TestBoxData.ksParam_idTestBox: oEntry.idTestBox },
348 sConfirm = 'Are you sure that you want to remove %s (%s)?' % (oEntry.sName, oEntry.ip) ),
349 ]
350
351 if oEntry.sOs not in [ 'win', 'os2', ] and oEntry.ip is not None:
352 aoActions.append(WuiLinkBase('ssh', 'ssh://vbox@%s' % (oEntry.ip,),));
353
354 return [ self._getCheckBoxColumn(iEntry, oEntry.idTestBox),
355 [ WuiSpanText('tmspan-name', oEntry.sName), WuiRawHtml('<br>'), '%s' % (oEntry.ip,),],
356 aoLom,
357 [
358 '' if oEntry.fEnabled else 'disabled / ',
359 oState,
360 WuiRawHtml('<br>'),
361 oSeen,
362 ],
363 oEntry.enmPendingCmd,
364 oComment,
365 WuiSvnLink(oEntry.iTestBoxScriptRev),
366 oEntry.formatPythonVersion(),
367 aoGroups,
368 aoOs,
369 oCpu,
370 sFeatures,
371 oEntry.cCpus if oEntry.cCpus is not None else 'N/A',
372 utils.formatNumberNbsp(oEntry.cMbMemory) + u'\u00a0MB' if oEntry.cMbMemory is not None else 'N/A',
373 utils.formatNumberNbsp(oEntry.cMbScratch) + u'\u00a0MB' if oEntry.cMbScratch is not None else 'N/A',
374 aoActions,
375 ];
376
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