Merge ~ltrager/maas:2.3_1722607_2 into maas:2.3
- Git
- lp:~ltrager/maas
- 2.3_1722607_2
- Merge into 2.3
Proposed by
Lee Trager
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Lee Trager | ||||||||
Approved revision: | c0f6a305f32b20c96de1804bacdc1642a9fdffaa | ||||||||
Merge reported by: | MAAS Lander | ||||||||
Merged at revision: | not available | ||||||||
Proposed branch: | ~ltrager/maas:2.3_1722607_2 | ||||||||
Merge into: | maas:2.3 | ||||||||
Prerequisite: | ~ltrager/maas:2.3_1722607_1 | ||||||||
Diff against target: |
949 lines (+436/-308) 7 files modified
src/maasserver/static/js/angular/controllers/node_details.js (+0/-125) src/maasserver/static/js/angular/controllers/node_results.js (+141/-11) src/maasserver/static/js/angular/controllers/tests/test_node_details.js (+1/-145) src/maasserver/static/js/angular/controllers/tests/test_node_results.js (+230/-0) src/maasserver/static/js/angular/factories/nodes.js (+13/-1) src/maasserver/static/js/angular/factories/tests/test_nodes.js (+32/-0) src/maasserver/static/partials/node-details.html (+19/-26) |
||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Blake Rouse (community) | Approve | ||
Review via email: mp+368110@code.launchpad.net |
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/maasserver/static/js/angular/controllers/node_details.js b/src/maasserver/static/js/angular/controllers/node_details.js |
2 | index 1b6bc0e..fa3ab7e 100644 |
3 | --- a/src/maasserver/static/js/angular/controllers/node_details.js |
4 | +++ b/src/maasserver/static/js/angular/controllers/node_details.js |
5 | @@ -111,13 +111,6 @@ angular.module('MAAS').controller('NodeDetailsController', [ |
6 | limit: 10 |
7 | }; |
8 | |
9 | - // Machine output section. |
10 | - $scope.machine_output = { |
11 | - viewable: false, |
12 | - selectedView: null, |
13 | - views: [] |
14 | - }; |
15 | - |
16 | // Updates the page title. |
17 | function updateTitle() { |
18 | if($scope.node && $scope.node.fqdn) { |
19 | @@ -244,68 +237,6 @@ angular.module('MAAS').controller('NodeDetailsController', [ |
20 | } |
21 | } |
22 | |
23 | - // Updates the machine output section. |
24 | - function updateMachineOutput() { |
25 | - // Set if it should even be viewable. |
26 | - $scope.machine_output.viewable = ( |
27 | - angular.isString($scope.node.summary_xml) || |
28 | - angular.isString($scope.node.summary_yaml) || |
29 | - (angular.isArray($scope.node.installation_results) && |
30 | - $scope.node.installation_results.length > 0)); |
31 | - |
32 | - // Grab the selected view name, so it can be kept the same if |
33 | - // possible. |
34 | - var viewName = null; |
35 | - if(angular.isObject($scope.machine_output.selectedView)) { |
36 | - viewName = $scope.machine_output.selectedView.name; |
37 | - } |
38 | - |
39 | - // If the viewName is empty, then a default one was not selected. |
40 | - // We want the installation output to be the default if possible. |
41 | - if(!angular.isString(viewName)) { |
42 | - viewName = "installation"; |
43 | - } |
44 | - |
45 | - // Setup the views that are viewable. |
46 | - $scope.machine_output.views = []; |
47 | - if(angular.isString($scope.node.summary_yaml)) { |
48 | - $scope.machine_output.views.push({ |
49 | - name: "summary_yaml", |
50 | - title: "Machine output (YAML)" |
51 | - }); |
52 | - } |
53 | - if(angular.isString($scope.node.summary_xml)) { |
54 | - $scope.machine_output.views.push({ |
55 | - name: "summary_xml", |
56 | - title: "Machine output (XML)" |
57 | - }); |
58 | - } |
59 | - if(angular.isArray($scope.node.installation_results) && |
60 | - $scope.node.installation_results.length > 0) { |
61 | - $scope.machine_output.views.push({ |
62 | - name: "installation", |
63 | - title: "Installation output" |
64 | - }); |
65 | - } |
66 | - |
67 | - // Set the selected view to its previous value or to the first |
68 | - // entry in the views list. |
69 | - var selectedView = null; |
70 | - angular.forEach($scope.machine_output.views, function(view) { |
71 | - if(view.name === viewName) { |
72 | - selectedView = view; |
73 | - } |
74 | - }); |
75 | - if(angular.isObject(selectedView)) { |
76 | - $scope.machine_output.selectedView = selectedView; |
77 | - } else if ($scope.machine_output.views.length > 0) { |
78 | - $scope.machine_output.selectedView = |
79 | - $scope.machine_output.views[0]; |
80 | - } else { |
81 | - $scope.machine_output.selectedView = null; |
82 | - } |
83 | - } |
84 | - |
85 | // Update the devices array on the scope based on the device children |
86 | // on the node. |
87 | function updateDevices() { |
88 | @@ -395,13 +326,6 @@ angular.module('MAAS').controller('NodeDetailsController', [ |
89 | |
90 | // Update the services when the services list is updated. |
91 | $scope.$watch("node.service_ids", updateServices); |
92 | - |
93 | - // Update the machine output view when summary, commissioning, or |
94 | - // installation results are updated on the node. |
95 | - $scope.$watch("node.summary_xml", updateMachineOutput); |
96 | - $scope.$watch("node.summary_yaml", updateMachineOutput); |
97 | - $scope.$watch("node.commissioning_results", updateMachineOutput); |
98 | - $scope.$watch("node.installation_results", updateMachineOutput); |
99 | } |
100 | |
101 | // Called when the node has been loaded. |
102 | @@ -411,7 +335,6 @@ angular.module('MAAS').controller('NodeDetailsController', [ |
103 | |
104 | updateTitle(); |
105 | updateSummary(); |
106 | - updateMachineOutput(); |
107 | updateServices(); |
108 | startWatching(); |
109 | |
110 | @@ -987,54 +910,6 @@ angular.module('MAAS').controller('NodeDetailsController', [ |
111 | } |
112 | }; |
113 | |
114 | - // Return the commissioning summary output data. |
115 | - $scope.getSummaryData = function(type) { |
116 | - // Can be called by angular before the node is set in the scope, |
117 | - // in that case return blank string. It will be called once the |
118 | - // node is set to get the correct information. |
119 | - if(!angular.isObject($scope.node)) { |
120 | - return ""; |
121 | - } |
122 | - return $scope.node["summary_" + type]; |
123 | - }; |
124 | - |
125 | - // Return the installation log data. |
126 | - $scope.getInstallationData = function() { |
127 | - // Can be called by angular before the node is set in the scope, |
128 | - // in that case return blank string. It will be called once the |
129 | - // node is set to get the correct information. |
130 | - if(!angular.isObject($scope.node)) { |
131 | - return ""; |
132 | - } |
133 | - // It is possible for the node to have multiple installation |
134 | - // results, but it is unused. Only one installation result will |
135 | - // exists for a node. Grab the first one in the array. |
136 | - var results = $scope.node.installation_results; |
137 | - if(!angular.isArray(results) || |
138 | - results.length === 0 || results[0].output === "") { |
139 | - switch($scope.node.installation_status) { |
140 | - case 0: |
141 | - return "System is booting..."; |
142 | - case 1: |
143 | - return "Installation has begun!"; |
144 | - case 2: |
145 | - return ("Installation has succeeded but no " + |
146 | - "output was given."); |
147 | - case 3: |
148 | - return ("Installation has failed and no output was " + |
149 | - "given."); |
150 | - case 4: |
151 | - return "Installation failed after 40 minutes."; |
152 | - case 5: |
153 | - return "Installation was aborted."; |
154 | - default: |
155 | - return ""; |
156 | - } |
157 | - } else { |
158 | - return results[0].output; |
159 | - } |
160 | - }; |
161 | - |
162 | // true if power error prevents the provided action |
163 | $scope.hasActionPowerError = function(actionName) { |
164 | if(!$scope.hasPowerError()) { |
165 | diff --git a/src/maasserver/static/js/angular/controllers/node_results.js b/src/maasserver/static/js/angular/controllers/node_results.js |
166 | index f3399d9..101e500 100644 |
167 | --- a/src/maasserver/static/js/angular/controllers/node_results.js |
168 | +++ b/src/maasserver/static/js/angular/controllers/node_results.js |
169 | @@ -11,39 +11,93 @@ angular.module('MAAS').controller('NodeResultsController', [ |
170 | NodeResultsManagerFactory, ManagerHelperService, ErrorService) { |
171 | |
172 | // NodeResultsManager that is loaded once the node is loaded. |
173 | - var nodeResultsManager = null; |
174 | + $scope.nodeResultsManager = null; |
175 | // References to manager data used in scope. |
176 | $scope.commissioning_results = null; |
177 | $scope.testing_results = null; |
178 | $scope.installation_results = null; |
179 | $scope.results = null; |
180 | |
181 | + // List of logs available. |
182 | + $scope.logs = { |
183 | + option: null, |
184 | + availableOptions: [] |
185 | + }; |
186 | + // Log content being displayed. |
187 | + $scope.logOutput = 'Loading...'; |
188 | + |
189 | // Initial values. |
190 | $scope.loaded = false; |
191 | $scope.resultsLoaded = false; |
192 | $scope.node = null; |
193 | |
194 | + function updateLogs() { |
195 | + var i; |
196 | + var option; |
197 | + var had_installation = $scope.logs.availableOptions.length === 3; |
198 | + $scope.logs.availableOptions.length = 0; |
199 | + // XXX ltrager 2017-12-01 - Only show the current installation log |
200 | + // if the machine is deploying, deployed, or failed deploying. The |
201 | + // logs page needs to be redesigned to show previous installation |
202 | + // results. |
203 | + if($scope.installation_results && |
204 | + $scope.installation_results.length > 0 && ( |
205 | + $scope.node.status_code === 6 || |
206 | + $scope.node.status_code === 9 || |
207 | + $scope.node.status_code === 11)) { |
208 | + $scope.logs.availableOptions.push({ |
209 | + 'title': 'Installation output', |
210 | + 'id': $scope.installation_results[0].id |
211 | + }); |
212 | + } |
213 | + $scope.logs.availableOptions.push({ |
214 | + 'title': 'Machine output (YAML)', |
215 | + 'id': 'summary_yaml' |
216 | + }); |
217 | + $scope.logs.availableOptions.push({ |
218 | + 'title': 'Machine output (XML)', |
219 | + 'id': 'summary_xml' |
220 | + }); |
221 | + if(!had_installation && |
222 | + $scope.logs.availableOptions.length === 3) { |
223 | + // A new installation log has appeared, show it. |
224 | + $scope.logs.option = $scope.logs.availableOptions[0]; |
225 | + }else if(!$scope.selectedLog || ( |
226 | + had_installation && $scope.logs.length === 2)) { |
227 | + // No longer in a deployed state. |
228 | + $scope.logs.option = $scope.logs.availableOptions[0]; |
229 | + } |
230 | + } |
231 | + |
232 | // Called once the node has loaded. |
233 | function nodeLoaded(node) { |
234 | $scope.node = node; |
235 | $scope.loaded = true; |
236 | // Get the NodeResultsManager and load it. |
237 | - nodeResultsManager = NodeResultsManagerFactory.getManager( |
238 | + $scope.nodeResultsManager = NodeResultsManagerFactory.getManager( |
239 | node, $scope.section.area); |
240 | - nodeResultsManager.loadItems().then(function() { |
241 | + $scope.nodeResultsManager.loadItems().then(function() { |
242 | $scope.commissioning_results = |
243 | - nodeResultsManager.commissioning_results; |
244 | - $scope.testing_results = nodeResultsManager.testing_results; |
245 | + $scope.nodeResultsManager.commissioning_results; |
246 | + $scope.testing_results = |
247 | + $scope.nodeResultsManager.testing_results; |
248 | $scope.installation_results = |
249 | - nodeResultsManager.installation_results; |
250 | - $scope.results = nodeResultsManager.results; |
251 | + $scope.nodeResultsManager.installation_results; |
252 | + $scope.results = $scope.nodeResultsManager.results; |
253 | + // Only load and monitor logs when on the logs page. |
254 | + if($scope.section.area === "logs") { |
255 | + updateLogs(); |
256 | + $scope.$watch("installation_results", updateLogs, true); |
257 | + $scope.$watch( |
258 | + "installation_results", $scope.updateLogOutput, true); |
259 | + } |
260 | $scope.resultsLoaded = true; |
261 | }); |
262 | } |
263 | |
264 | if($routeParams.type === 'controller') { |
265 | $scope.nodesManager = ControllersManager; |
266 | - }else{ |
267 | + } else { |
268 | $scope.nodesManager = MachinesManager; |
269 | } |
270 | // Load nodes manager. |
271 | @@ -55,7 +109,7 @@ angular.module('MAAS').controller('NodeResultsController', [ |
272 | if(angular.isObject(activeNode) && |
273 | activeNode.system_id === $routeParams.system_id) { |
274 | nodeLoaded(activeNode); |
275 | - }else{ |
276 | + } else { |
277 | $scope.nodesManager.setActiveItem( |
278 | $routeParams.system_id).then(function(node) { |
279 | nodeLoaded(node); |
280 | @@ -65,12 +119,88 @@ angular.module('MAAS').controller('NodeResultsController', [ |
281 | } |
282 | }); |
283 | |
284 | + $scope.updateLogOutput = function() { |
285 | + $scope.logOutput = "Loading..."; |
286 | + if(!$scope.node) { |
287 | + return; |
288 | + }else if($scope.logs.option.id === 'summary_xml') { |
289 | + $scope.nodesManager.getSummaryXML($scope.node).then( |
290 | + function(output) { |
291 | + $scope.logOutput = output; |
292 | + }); |
293 | + }else if($scope.logs.option.id === 'summary_yaml') { |
294 | + $scope.nodesManager.getSummaryYAML($scope.node).then( |
295 | + function(output) { |
296 | + $scope.logOutput = output; |
297 | + }); |
298 | + } else { |
299 | + var result = null; |
300 | + var i, j; |
301 | + // Find the installation result to be displayed. |
302 | + for(i = 0; i < $scope.installation_results.length; i++) { |
303 | + var hlist = $scope.installation_results[i].history_list; |
304 | + for(j = 0; j < hlist.length; j++) { |
305 | + if(hlist[j].id === $scope.logs.option.id) { |
306 | + result = hlist[j]; |
307 | + break; |
308 | + } |
309 | + } |
310 | + if(result) { |
311 | + break; |
312 | + } |
313 | + } |
314 | + switch(result.status) { |
315 | + case 0: |
316 | + $scope.logOutput = "System is booting..."; |
317 | + break; |
318 | + case 1: |
319 | + $scope.logOutput = "Installation has begun!"; |
320 | + break; |
321 | + case 2: |
322 | + $scope.nodeResultsManager.get_result_data( |
323 | + result.id, 'combined').then(function(output) { |
324 | + if(output === '') { |
325 | + $scope.logOutput = |
326 | + "Installation has succeeded but " + |
327 | + "no output was given."; |
328 | + } else { |
329 | + $scope.logOutput = output; |
330 | + } |
331 | + }); |
332 | + break; |
333 | + case 3: |
334 | + $scope.nodeResultsManager.get_result_data( |
335 | + result.id, 'combined').then(function(output) { |
336 | + if(output === '') { |
337 | + $scope.logOutput = |
338 | + "Installation has failed and no " + |
339 | + "output was given."; |
340 | + } else { |
341 | + $scope.logOutput = output; |
342 | + } |
343 | + }); |
344 | + break; |
345 | + case 4: |
346 | + $scope.logOutput = |
347 | + "Installation failed after 40 minutes."; |
348 | + break; |
349 | + case 5: |
350 | + $scope.logOutput = "Installation was aborted."; |
351 | + break; |
352 | + default: |
353 | + $scope.logOutput = "BUG: Unknown log status " + |
354 | + result.status; |
355 | + break; |
356 | + } |
357 | + } |
358 | + }; |
359 | + |
360 | // Destroy the NodeResultsManager when the scope is destroyed. This is |
361 | // so the client will not recieve any more notifications about results |
362 | // from this node. |
363 | $scope.$on("$destroy", function() { |
364 | - if(angular.isObject(nodeResultsManager)) { |
365 | - nodeResultsManager.destroy(); |
366 | + if(angular.isObject($scope.nodeResultsManager)) { |
367 | + $scope.nodeResultsManager.destroy(); |
368 | } |
369 | }); |
370 | }]); |
371 | diff --git a/src/maasserver/static/js/angular/controllers/tests/test_node_details.js b/src/maasserver/static/js/angular/controllers/tests/test_node_details.js |
372 | index 00b3c0b..1947106 100644 |
373 | --- a/src/maasserver/static/js/angular/controllers/tests/test_node_details.js |
374 | +++ b/src/maasserver/static/js/angular/controllers/tests/test_node_details.js |
375 | @@ -253,15 +253,6 @@ describe("NodeDetailsController", function() { |
376 | }); |
377 | }); |
378 | |
379 | - it("sets initial values for machine output section", function() { |
380 | - var controller = makeController(); |
381 | - expect($scope.machine_output).toEqual({ |
382 | - viewable: false, |
383 | - selectedView: null, |
384 | - views: [] |
385 | - }); |
386 | - }); |
387 | - |
388 | it("sets initial area to routeParams value", function() { |
389 | $routeParams.area = makeName("area"); |
390 | var controller = makeController(); |
391 | @@ -452,71 +443,6 @@ describe("NodeDetailsController", function() { |
392 | expect($scope.power.editing).toBe(false); |
393 | }); |
394 | |
395 | - it("machine output not visible if all required data missing", function() { |
396 | - var controller = makeControllerResolveSetActiveItem(); |
397 | - expect($scope.machine_output.viewable).toBe(false); |
398 | - }); |
399 | - |
400 | - it("machine output visible if summary_xml and summary_yaml", function() { |
401 | - node.summary_xml = node.summary_yaml = "summary"; |
402 | - var controller = makeControllerResolveSetActiveItem(); |
403 | - expect($scope.machine_output.viewable).toBe(true); |
404 | - }); |
405 | - |
406 | - it("machine output visible if installation_results", function() { |
407 | - node.installation_results.push({}); |
408 | - var controller = makeControllerResolveSetActiveItem(); |
409 | - expect($scope.machine_output.viewable).toBe(true); |
410 | - }); |
411 | - |
412 | - it("machine output not visible if installation_results not an array", |
413 | - function() { |
414 | - node.installation_results = undefined; |
415 | - var controller = makeControllerResolveSetActiveItem(); |
416 | - expect($scope.machine_output.viewable).toBe(false); |
417 | - }); |
418 | - |
419 | - it("machine output summary view available if summary_xml", |
420 | - function() { |
421 | - node.summary_xml = "summary_xml"; |
422 | - var controller = makeControllerResolveSetActiveItem(); |
423 | - expect($scope.machine_output.views).toEqual([{ |
424 | - name: "summary_xml", |
425 | - title: "Machine output (XML)" |
426 | - }]); |
427 | - }); |
428 | - |
429 | - it("machine output summary view available if summary_yaml", |
430 | - function() { |
431 | - node.summary_yaml = "summary_yaml"; |
432 | - var controller = makeControllerResolveSetActiveItem(); |
433 | - expect($scope.machine_output.views).toEqual([{ |
434 | - name: "summary_yaml", |
435 | - title: "Machine output (YAML)" |
436 | - }]); |
437 | - }); |
438 | - |
439 | - it("machine output installation view available if installation_results", |
440 | - function() { |
441 | - node.installation_results.push({}); |
442 | - var controller = makeControllerResolveSetActiveItem(); |
443 | - expect($scope.machine_output.views).toEqual([{ |
444 | - name: "installation", |
445 | - title: "Installation output" |
446 | - }]); |
447 | - }); |
448 | - |
449 | - it("machine output install view is always selected first if possible", |
450 | - function() { |
451 | - node.summary_xml = node.summary_yaml = "summary"; |
452 | - node.installation_results.push({}); |
453 | - var controller = makeControllerResolveSetActiveItem(); |
454 | - expect($scope.machine_output.selectedView).toEqual({ |
455 | - name: "installation", |
456 | - title: "Installation output" |
457 | - }); |
458 | - }); |
459 | - |
460 | it("starts watching once setActiveItem resolves", function() { |
461 | var setActiveDefer = $q.defer(); |
462 | spyOn(MachinesManager, "setActiveItem").and.returnValue( |
463 | @@ -553,11 +479,7 @@ describe("NodeDetailsController", function() { |
464 | "node.zone.id", |
465 | "node.power_type", |
466 | "node.power_parameters", |
467 | - "node.service_ids", |
468 | - "node.summary_xml", |
469 | - "node.summary_yaml", |
470 | - "node.commissioning_results", |
471 | - "node.installation_results" |
472 | + "node.service_ids" |
473 | ]); |
474 | expect(watchCollections).toEqual([ |
475 | $scope.summary.architecture.options, |
476 | @@ -2180,72 +2102,6 @@ describe("NodeDetailsController", function() { |
477 | }); |
478 | }); |
479 | |
480 | - describe("getSummaryData", function() { |
481 | - |
482 | - it("returns blank string if node is null", function() { |
483 | - var controller = makeController(); |
484 | - expect($scope.getSummaryData()).toBe(""); |
485 | - }); |
486 | - |
487 | - it("returns summary_xml", function() { |
488 | - var controller = makeController(); |
489 | - $scope.node = makeNode(); |
490 | - var summary_xml = {}; |
491 | - $scope.node.summary_xml = summary_xml; |
492 | - expect($scope.getSummaryData("xml")).toBe(summary_xml); |
493 | - }); |
494 | - |
495 | - it("returns summary_yaml when summaryType equal yaml", function() { |
496 | - var controller = makeController(); |
497 | - $scope.node = makeNode(); |
498 | - var summary_yaml = {}; |
499 | - $scope.node.summary_yaml = summary_yaml; |
500 | - expect($scope.getSummaryData("yaml")).toBe(summary_yaml); |
501 | - }); |
502 | - }); |
503 | - |
504 | - describe("getInstallationData", function() { |
505 | - |
506 | - it("returns blank string if node is null", function() { |
507 | - var controller = makeController(); |
508 | - expect($scope.getInstallationData()).toBe(""); |
509 | - }); |
510 | - |
511 | - it("returns blank string if installation results not an array", |
512 | - function() { |
513 | - var controller = makeController(); |
514 | - $scope.node = makeNode(); |
515 | - $scope.node.installation_results = undefined; |
516 | - expect($scope.getInstallationData()).toBe(""); |
517 | - }); |
518 | - |
519 | - it("returns blank string if no installation results", function() { |
520 | - var controller = makeController(); |
521 | - $scope.node = makeNode(); |
522 | - expect($scope.getInstallationData()).toBe(""); |
523 | - }); |
524 | - |
525 | - it("returns first installation result data", function() { |
526 | - var controller = makeController(); |
527 | - $scope.node = makeNode(); |
528 | - var install_result = {}; |
529 | - $scope.node.installation_results.push({ |
530 | - output: install_result |
531 | - }); |
532 | - $scope.node.installation_results.push({ |
533 | - output: {} |
534 | - }); |
535 | - expect($scope.getInstallationData()).toBe(install_result); |
536 | - }); |
537 | - |
538 | - it("returns status message when no output and status", function() { |
539 | - var controller = makeController(); |
540 | - $scope.node = makeNode(); |
541 | - $scope.node.installation_status = makeInteger(0, 5); |
542 | - expect($scope.getInstallationData()).not.toBe(""); |
543 | - }); |
544 | - }); |
545 | - |
546 | describe("getServiceClass", function() { |
547 | |
548 | it("returns 'none' if null", function() { |
549 | diff --git a/src/maasserver/static/js/angular/controllers/tests/test_node_results.js b/src/maasserver/static/js/angular/controllers/tests/test_node_results.js |
550 | index b677ae5..f2f44d7 100644 |
551 | --- a/src/maasserver/static/js/angular/controllers/tests/test_node_results.js |
552 | +++ b/src/maasserver/static/js/angular/controllers/tests/test_node_results.js |
553 | @@ -49,6 +49,35 @@ describe("NodeResultsController", function() { |
554 | return node; |
555 | } |
556 | |
557 | + // Make a result. |
558 | + function makeResult(type, status) { |
559 | + if(type === null) { |
560 | + type = makeInteger(0, 3); |
561 | + } |
562 | + if(status === null) { |
563 | + status = makeInteger(0, 8); |
564 | + } |
565 | + var id = makeInteger(0, 1000); |
566 | + var result = { |
567 | + id: id, |
568 | + name: makeName("name"), |
569 | + type: type, |
570 | + status: status, |
571 | + history_list: [{ |
572 | + id: id, |
573 | + status: status |
574 | + }] |
575 | + }; |
576 | + var i; |
577 | + for(i = 0; i < 3; i++) { |
578 | + result.history_list.push({ |
579 | + id: makeInteger(0, 1000), |
580 | + status: makeInteger(0, 8) |
581 | + }); |
582 | + } |
583 | + return result; |
584 | + } |
585 | + |
586 | // Makes the NodeResultsController |
587 | function makeController(loadManagerDefer) { |
588 | var loadManager = spyOn(ManagerHelperService, "loadManager"); |
589 | @@ -88,6 +117,9 @@ describe("NodeResultsController", function() { |
590 | expect($scope.testing_results).toBeNull(); |
591 | expect($scope.installation_results).toBeNull(); |
592 | expect($scope.results).toBeNull(); |
593 | + expect($scope.logs.option).toBeNull(); |
594 | + expect($scope.logs.availableOptions).toEqual([]); |
595 | + expect($scope.logOutput).toEqual("Loading..."); |
596 | expect($scope.loaded).toBe(false); |
597 | expect($scope.resultsLoaded).toBe(false); |
598 | expect($scope.node).toBeNull(); |
599 | @@ -101,6 +133,9 @@ describe("NodeResultsController", function() { |
600 | expect($scope.testing_results).toBeNull(); |
601 | expect($scope.installation_results).toBeNull(); |
602 | expect($scope.results).toBeNull(); |
603 | + expect($scope.logs.option).toBeNull(); |
604 | + expect($scope.logs.availableOptions).toEqual([]); |
605 | + expect($scope.logOutput).toEqual("Loading..."); |
606 | expect($scope.loaded).toBe(false); |
607 | expect($scope.resultsLoaded).toBe(false); |
608 | expect($scope.node).toBeNull(); |
609 | @@ -203,4 +238,199 @@ describe("NodeResultsController", function() { |
610 | $rootScope.$digest(); |
611 | expect($scope.resultsLoaded).toBe(true); |
612 | }); |
613 | + |
614 | + describe("updateLogs", function() { |
615 | + it("only runs on logs page", function() { |
616 | + var defer = $q.defer(); |
617 | + var controller = makeController(defer); |
618 | + MachinesManager._activeItem = node; |
619 | + var manager = NodeResultsManagerFactory.getManager(node); |
620 | + var loadDefer = $q.defer(); |
621 | + |
622 | + defer.resolve(); |
623 | + $rootScope.$digest(); |
624 | + loadDefer.resolve(); |
625 | + $rootScope.$digest(); |
626 | + expect($scope.logs.availableOptions).toEqual([]); |
627 | + }); |
628 | + |
629 | + it("loads summary", function() { |
630 | + var defer = $q.defer(); |
631 | + var controller = makeController(defer); |
632 | + $scope.section = {area: "logs"}; |
633 | + MachinesManager._activeItem = node; |
634 | + webSocket.returnData.push(makeFakeResponse([])); |
635 | + var manager = NodeResultsManagerFactory.getManager(node); |
636 | + |
637 | + defer.resolve(); |
638 | + $rootScope.$digest(); |
639 | + var expectFunc; |
640 | + expectFunc = function() { |
641 | + if($scope.resultsLoaded) { |
642 | + expect($scope.logs.availableOptions).toEqual([ |
643 | + { |
644 | + title: 'Machine output (YAML)', |
645 | + id: 'summary_yaml' |
646 | + }, |
647 | + { |
648 | + title: 'Machine output (XML)', |
649 | + id: 'summary_xml' |
650 | + } |
651 | + ]); |
652 | + expect($scope.logs.option).toEqual({ |
653 | + title: 'Machine output (YAML)', |
654 | + id: 'summary_yaml' |
655 | + }); |
656 | + }else{ |
657 | + setTimeout(expectFunc); |
658 | + } |
659 | + }; |
660 | + setTimeout(expectFunc); |
661 | + }); |
662 | + }); |
663 | + |
664 | + describe("updateLogOutput", function() { |
665 | + it("sets to loading when no node", function() { |
666 | + var controller = makeController(); |
667 | + $scope.updateLogOutput(); |
668 | + expect($scope.logOutput).toEqual("Loading..."); |
669 | + }); |
670 | + |
671 | + it("sets summary xml", function() { |
672 | + var defer = $q.defer(); |
673 | + var controller = makeController(defer); |
674 | + MachinesManager._activeItem = node; |
675 | + var managerDefer = $q.defer(); |
676 | + $scope.logs = {option: {id: "summary_xml"}}; |
677 | + spyOn(MachinesManager, "getSummaryXML").and.returnValue( |
678 | + managerDefer.promise); |
679 | + |
680 | + defer.resolve(); |
681 | + $rootScope.$digest(); |
682 | + managerDefer.resolve(); |
683 | + $rootScope.$digest(); |
684 | + |
685 | + $scope.updateLogOutput(); |
686 | + expect(MachinesManager.getSummaryXML).toHaveBeenCalledWith(node); |
687 | + }); |
688 | + |
689 | + it("sets summary yaml", function() { |
690 | + var defer = $q.defer(); |
691 | + var controller = makeController(defer); |
692 | + MachinesManager._activeItem = node; |
693 | + var managerDefer = $q.defer(); |
694 | + $scope.logs = {option: {id: "summary_yaml"}}; |
695 | + spyOn(MachinesManager, "getSummaryYAML").and.returnValue( |
696 | + managerDefer.promise); |
697 | + |
698 | + defer.resolve(); |
699 | + $rootScope.$digest(); |
700 | + managerDefer.resolve(); |
701 | + $rootScope.$digest(); |
702 | + |
703 | + $scope.updateLogOutput(); |
704 | + expect(MachinesManager.getSummaryYAML).toHaveBeenCalledWith(node); |
705 | + }); |
706 | + |
707 | + it("sets system booting", function() { |
708 | + var controller = makeController(); |
709 | + var installation_result = makeResult(1, 0); |
710 | + $scope.installation_results = [installation_result]; |
711 | + $scope.node = node; |
712 | + $scope.logs = {option: {id: installation_result.id}}; |
713 | + |
714 | + $scope.updateLogOutput(); |
715 | + expect($scope.logOutput).toEqual("System is booting..."); |
716 | + }); |
717 | + |
718 | + it("sets installation has begun", function() { |
719 | + var controller = makeController(); |
720 | + var installation_result = makeResult(1, 1); |
721 | + $scope.installation_results = [installation_result]; |
722 | + $scope.node = node; |
723 | + $scope.logs = {option: {id: installation_result.id}}; |
724 | + |
725 | + $scope.updateLogOutput(); |
726 | + expect($scope.logOutput).toEqual("Installation has begun!"); |
727 | + }); |
728 | + |
729 | + it("sets installation output succeeded", function() { |
730 | + var defer = $q.defer(); |
731 | + var controller = makeController(defer); |
732 | + var installation_result = makeResult(1, 2); |
733 | + MachinesManager._activeItem = node; |
734 | + var manager = NodeResultsManagerFactory.getManager(node); |
735 | + var managerDefer = $q.defer(); |
736 | + spyOn(manager, "get_result_data").and.returnValue( |
737 | + managerDefer.promise); |
738 | + |
739 | + defer.resolve(); |
740 | + $rootScope.$digest(); |
741 | + managerDefer.resolve(); |
742 | + $rootScope.$digest(); |
743 | + |
744 | + $scope.installation_results = [installation_result]; |
745 | + $scope.logs = {option: {id: installation_result.id}}; |
746 | + $scope.updateLogOutput(); |
747 | + expect(manager.get_result_data).toHaveBeenCalledWith( |
748 | + installation_result.id, 'combined'); |
749 | + }); |
750 | + |
751 | + it("sets installation output failed", function() { |
752 | + var defer = $q.defer(); |
753 | + var controller = makeController(defer); |
754 | + var installation_result = makeResult(1, 3); |
755 | + MachinesManager._activeItem = node; |
756 | + var manager = NodeResultsManagerFactory.getManager(node); |
757 | + var managerDefer = $q.defer(); |
758 | + spyOn(manager, "get_result_data").and.returnValue( |
759 | + managerDefer.promise); |
760 | + |
761 | + defer.resolve(); |
762 | + $rootScope.$digest(); |
763 | + managerDefer.resolve(); |
764 | + $rootScope.$digest(); |
765 | + |
766 | + $scope.installation_results = [installation_result]; |
767 | + $scope.logs = {option: {id: installation_result.id}}; |
768 | + $scope.updateLogOutput(); |
769 | + expect(manager.get_result_data).toHaveBeenCalledWith( |
770 | + installation_result.id, 'combined'); |
771 | + }); |
772 | + |
773 | + it("sets timed out", function() { |
774 | + var controller = makeController(); |
775 | + var installation_result = makeResult(1, 4); |
776 | + $scope.installation_results = [installation_result]; |
777 | + $scope.node = node; |
778 | + $scope.logs = {option: {id: installation_result.id}}; |
779 | + |
780 | + $scope.updateLogOutput(); |
781 | + expect($scope.logOutput).toEqual( |
782 | + "Installation failed after 40 minutes."); |
783 | + }); |
784 | + |
785 | + it("sets installation aborted", function() { |
786 | + var controller = makeController(); |
787 | + var installation_result = makeResult(1, 5); |
788 | + $scope.installation_results = [installation_result]; |
789 | + $scope.node = node; |
790 | + $scope.logs = {option: {id: installation_result.id}}; |
791 | + |
792 | + $scope.updateLogOutput(); |
793 | + expect($scope.logOutput).toEqual("Installation was aborted."); |
794 | + }); |
795 | + |
796 | + it("sets unknown status", function() { |
797 | + var controller = makeController(); |
798 | + var installation_result = makeResult(1, makeInteger(6, 100)); |
799 | + $scope.installation_results = [installation_result]; |
800 | + $scope.node = node; |
801 | + $scope.logs = {option: {id: installation_result.id}}; |
802 | + |
803 | + $scope.updateLogOutput(); |
804 | + expect($scope.logOutput).toEqual( |
805 | + "BUG: Unknown log status " + installation_result.status); |
806 | + }); |
807 | + }); |
808 | }); |
809 | diff --git a/src/maasserver/static/js/angular/factories/nodes.js b/src/maasserver/static/js/angular/factories/nodes.js |
810 | index e1406e8..1b4c0de 100644 |
811 | --- a/src/maasserver/static/js/angular/factories/nodes.js |
812 | +++ b/src/maasserver/static/js/angular/factories/nodes.js |
813 | @@ -1,4 +1,4 @@ |
814 | -/* Copyright 2015-2016 Canonical Ltd. This software is licensed under the |
815 | +/* Copyright 2015-2017 Canonical Ltd. This software is licensed under the |
816 | * GNU Affero General Public License version 3 (see the file LICENSE). |
817 | * |
818 | * MAAS Nodes Manager |
819 | @@ -337,5 +337,17 @@ angular.module('MAAS').service( |
820 | this._handler + ".set_boot_disk", params); |
821 | }; |
822 | |
823 | + NodesManager.prototype.getSummaryXML = function(node) { |
824 | + return RegionConnection.callMethod( |
825 | + this._handler + ".get_summary_xml", |
826 | + {"system_id": node.system_id}); |
827 | + }; |
828 | + |
829 | + NodesManager.prototype.getSummaryYAML = function(node) { |
830 | + return RegionConnection.callMethod( |
831 | + this._handler + ".get_summary_yaml", |
832 | + {"system_id": node.system_id}); |
833 | + }; |
834 | + |
835 | return NodesManager; |
836 | }]); |
837 | diff --git a/src/maasserver/static/js/angular/factories/tests/test_nodes.js b/src/maasserver/static/js/angular/factories/tests/test_nodes.js |
838 | index 39dce06..77ce066 100644 |
839 | --- a/src/maasserver/static/js/angular/factories/tests/test_nodes.js |
840 | +++ b/src/maasserver/static/js/angular/factories/tests/test_nodes.js |
841 | @@ -826,4 +826,36 @@ describe("NodesManager", function() { |
842 | }); |
843 | }); |
844 | }); |
845 | + |
846 | + describe("getSummaryXML", function() { |
847 | + |
848 | + it("calls machine.get_summary_xml", function(done) { |
849 | + var fakemachine = makemachine(); |
850 | + var summary_xml = makeName("summary_xml"); |
851 | + webSocket.returnData.push(makeFakeResponse(summary_xml)); |
852 | + MachinesManager.getSummaryXML(fakemachine).then(function(output) { |
853 | + var sentObject = angular.fromJson(webSocket.sentData[0]); |
854 | + expect(sentObject.method).toBe("machine.get_summary_xml"); |
855 | + expect(sentObject.params.system_id).toBe(fakemachine.system_id); |
856 | + expect(output).toBe(summary_xml); |
857 | + done(); |
858 | + }); |
859 | + }); |
860 | + }); |
861 | + |
862 | + describe("getSummaryYAML", function() { |
863 | + |
864 | + it("calls machine.get_summary_yaml", function(done) { |
865 | + var fakemachine = makemachine(); |
866 | + var summary_yaml = makeName("summary_yaml"); |
867 | + webSocket.returnData.push(makeFakeResponse(summary_yaml)); |
868 | + MachinesManager.getSummaryYAML(fakemachine).then(function(output) { |
869 | + var sentObject = angular.fromJson(webSocket.sentData[0]); |
870 | + expect(sentObject.method).toBe("machine.get_summary_yaml"); |
871 | + expect(sentObject.params.system_id).toBe(fakemachine.system_id); |
872 | + expect(output).toBe(summary_yaml); |
873 | + done(); |
874 | + }); |
875 | + }); |
876 | + }); |
877 | }); |
878 | diff --git a/src/maasserver/static/partials/node-details.html b/src/maasserver/static/partials/node-details.html |
879 | index 9e4c16e..22dda29 100755 |
880 | --- a/src/maasserver/static/partials/node-details.html |
881 | +++ b/src/maasserver/static/partials/node-details.html |
882 | @@ -219,9 +219,9 @@ |
883 | <button role="tab" class="page-navigation__link" data-ng-if="node.testing_script_count > 0" |
884 | data-ng-class="{ 'is-active': section.area === 'testing'}" |
885 | data-ng-click="section.area = 'testing'"><span data-maas-script-status="script-status" data-script-status="node.testing_status"></span> Hardware tests</button> |
886 | - <button role="tab" class="page-navigation__link" data-ng-if="machine_output.viewable" |
887 | + <button role="tab" class="page-navigation__link" data-ng-if="node.has_logs" |
888 | data-ng-class="{ 'is-active': section.area === 'logs'}" |
889 | - data-ng-click="section.area = 'logs'"><span data-maas-script-status="script-status" data-script-status="node.installation_status" data-ng-if="node.installation_results.length > 0"></span> Logs</button> |
890 | + data-ng-click="section.area = 'logs'"><span data-maas-script-status="script-status" data-script-status="node.installation_status" data-ng-if="node.installation_status !== -1"></span> Logs</button> |
891 | <button role="tab" class="page-navigation__link" data-ng-if="!isDevice" |
892 | data-ng-class="{ 'is-active': section.area === 'events'}" |
893 | data-ng-click="section.area = 'events'">Events</button> |
894 | @@ -257,7 +257,7 @@ |
895 | </div> |
896 | <div class="p-notification--warning twelve-col" data-ng-if="showFailedTestWarning()"> |
897 | <p class="p-notification__response"> |
898 | - <span class="p-notification__status">Warning:</span>Machine has failed tests; use with caution!</p> |
899 | + <span class="p-notification__status">Warning:</span>Machine has failed tests; use with caution!</p> |
900 | </div> |
901 | <div class="twelve-col u-equal-height" data-ng-if="isDevice"> |
902 | <div class="four-col action-card action-card--positionable u-border--solid"> |
903 | @@ -2393,30 +2393,23 @@ |
904 | </div> |
905 | </section> |
906 | <section class="row" data-ng-if="section.area === 'logs'"> |
907 | - <div class="wrapper--inner"> |
908 | - <div class="twelve-col"> |
909 | - <div data-maas-cta="machine_output.views" |
910 | - data-ng-model="machine_output.selectedView"> |
911 | - </div> |
912 | - </div> |
913 | - </div> |
914 | - <div class="wrapper--inner" data-ng-if="machine_output.selectedView.name == 'summary_yaml'"> |
915 | - <div class="twelve-col"> |
916 | - <pre class="code-block code-block--numbering code-block--terminal" data-maas-code-lines="getSummaryData('yaml')"> |
917 | - </pre> |
918 | - </div> |
919 | - </div> |
920 | - <div class="wrapper--inner" data-ng-if="machine_output.selectedView.name == 'summary_xml'"> |
921 | - <div class="twelve-col"> |
922 | - <pre class="code-block code-block--numbering code-block--terminal" data-maas-code-lines="getSummaryData('xml')"> |
923 | - </pre> |
924 | - </div> |
925 | - </div> |
926 | - <div class="wrapper--inner" data-ng-if="machine_output.selectedView.name == 'installation'"> |
927 | - <div class="twelve-col"> |
928 | - <pre class="code-block code-block--numbering code-block--terminal" data-maas-code-lines="getInstallationData()"></pre> |
929 | + <div data-ng-controller="NodeResultsController"> |
930 | + <div class="twelve-col" data-ng-if="!resultsLoaded"> |
931 | + <p class="u-text--loading"><i class="icon icon--loading u-animation--spin"></i> Loading...</p> |
932 | + </div> |
933 | + <div data-ng-if="resultsLoaded"> |
934 | + <div class="wrapper--inner"> |
935 | + <div class="twelve-col"> |
936 | + <div data-maas-cta="logs.availableOptions" data-ng-model="logs.option" data-ng-change="updateLogOutput()"> |
937 | + </div> |
938 | + </div> |
939 | + <div class="wrapper--inner"> |
940 | + <div class="twelve-col"> |
941 | + <pre class="code-block code-block--numbering code-block--terminal" data-maas-code-lines="logOutput"></pre> |
942 | + </div> |
943 | + </div> |
944 | + </div> |
945 | </div> |
946 | - </div> |
947 | </section> |
948 | <section class="row" data-ng-if="section.area === 'commissioning'"> |
949 | <div data-maas-script-results-list="script-results"></div> |
Looks good.