Merge lp:~blake-rouse/maas/fix-1592137 into lp:~maas-committers/maas/trunk
- fix-1592137
- Merge into trunk
Proposed by
Blake Rouse
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Blake Rouse | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 5127 | ||||
Proposed branch: | lp:~blake-rouse/maas/fix-1592137 | ||||
Merge into: | lp:~maas-committers/maas/trunk | ||||
Diff against target: |
725 lines (+450/-97) 7 files modified
src/maasserver/enum.py (+7/-3) src/maasserver/static/js/angular/controllers/subnet_details.js (+91/-5) src/maasserver/static/js/angular/controllers/tests/test_subnet_details.js (+154/-0) src/maasserver/static/js/angular/services/converter.js (+55/-0) src/maasserver/static/js/angular/services/tests/test_converter.js (+104/-0) src/maasserver/static/js/angular/services/validation.js (+15/-55) src/maasserver/static/partials/subnet-details.html (+24/-34) |
||||
To merge this branch: | bzr merge lp:~blake-rouse/maas/fix-1592137 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mike Pontillo (community) | Approve | ||
Jeffrey C Jones (community) | Approve | ||
Review via email: mp+297468@code.launchpad.net |
Commit message
Add the ability to sort the IP address table on the subnet details page.
Description of the change
To post a comment you must log in.
Revision history for this message
Mike Pontillo (mpontillo) wrote : | # |
Looks really good!
I made a number of comments below; nothing really blocking, but some things to consider and some minor cleanup.
review:
Approve
Revision history for this message
Blake Rouse (blake-rouse) wrote : | # |
Thanks for the reviews. Addressed all comments.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/maasserver/enum.py' |
2 | --- src/maasserver/enum.py 2016-04-11 16:23:26 +0000 |
3 | +++ src/maasserver/enum.py 2016-06-16 14:50:25 +0000 |
4 | @@ -134,6 +134,8 @@ |
5 | REGION_AND_RACK_CONTROLLER = 4 |
6 | |
7 | |
8 | +# This is copied in static/js/angular/controllers/subnet_details.js. If you |
9 | +# update any choices you also need to update the controller. |
10 | NODE_TYPE_CHOICES = ( |
11 | (NODE_TYPE.MACHINE, "Machine"), |
12 | (NODE_TYPE.DEVICE, "Device"), |
13 | @@ -226,12 +228,14 @@ |
14 | DISCOVERED = 6 |
15 | |
16 | |
17 | +# This is copied in static/js/angular/controllers/subnet_details.js. If you |
18 | +# update any choices you also need to update the controller. |
19 | IPADDRESS_TYPE_CHOICES = ( |
20 | - (IPADDRESS_TYPE.AUTO, "Auto"), |
21 | - (IPADDRESS_TYPE.STICKY, "Sticky"), |
22 | + (IPADDRESS_TYPE.AUTO, "Automatic"), |
23 | + (IPADDRESS_TYPE.STICKY, "Static"), |
24 | (IPADDRESS_TYPE.USER_RESERVED, "User reserved"), |
25 | (IPADDRESS_TYPE.DHCP, "DHCP"), |
26 | - (IPADDRESS_TYPE.DISCOVERED, "Discovered"), |
27 | + (IPADDRESS_TYPE.DISCOVERED, "Observed"), |
28 | ) |
29 | |
30 | |
31 | |
32 | === modified file 'src/maasserver/static/js/angular/controllers/subnet_details.js' |
33 | --- src/maasserver/static/js/angular/controllers/subnet_details.js 2016-06-09 17:18:10 +0000 |
34 | +++ src/maasserver/static/js/angular/controllers/subnet_details.js 2016-06-16 14:50:25 +0000 |
35 | @@ -8,10 +8,11 @@ |
36 | '$scope', '$rootScope', '$routeParams', '$filter', '$location', |
37 | 'SubnetsManager', 'IPRangesManager', 'SpacesManager', 'VLANsManager', |
38 | 'UsersManager', 'FabricsManager', 'ManagerHelperService', 'ErrorService', |
39 | + 'ConverterService', |
40 | function( |
41 | $scope, $rootScope, $routeParams, $filter, $location, SubnetsManager, |
42 | IPRangesManager, SpacesManager, VLANsManager, UsersManager, |
43 | - FabricsManager, ManagerHelperService, ErrorService) { |
44 | + FabricsManager, ManagerHelperService, ErrorService, ConverterService) { |
45 | |
46 | // Set title and page. |
47 | $rootScope.title = "Loading..."; |
48 | @@ -29,10 +30,29 @@ |
49 | $scope.spaces = SpacesManager.getItems(); |
50 | $scope.vlans = VLANsManager.getItems(); |
51 | $scope.fabrics = FabricsManager.getItems(); |
52 | + $scope.reverse = false; |
53 | $scope.newRange = null; |
54 | $scope.editIPRange = null; |
55 | $scope.deleteIPRange = null; |
56 | |
57 | + // Alloc type mapping. |
58 | + var ALLOC_TYPES = { |
59 | + 0: 'Automatic', |
60 | + 1: 'Static', |
61 | + 4: 'User reserved', |
62 | + 5: 'DHCP', |
63 | + 6: 'Observed' |
64 | + }; |
65 | + |
66 | + // Node type mapping. |
67 | + var NODE_TYPES = { |
68 | + 0: 'Machine', |
69 | + 1: 'Device', |
70 | + 2: 'Rack controller', |
71 | + 3: 'Region controller', |
72 | + 4: 'Rack and region controller' |
73 | + }; |
74 | + |
75 | // Updates the page title. |
76 | function updateTitle() { |
77 | subnet = $scope.subnet; |
78 | @@ -44,10 +64,75 @@ |
79 | } |
80 | } |
81 | |
82 | - $scope.isSuperUser = function() { |
83 | - return UsersManager.isSuperUser(); |
84 | - }; |
85 | - |
86 | + // Update the IP version of the CIDR. |
87 | + function updateIPVersion() { |
88 | + var ip = $scope.subnet.cidr.split('/')[0]; |
89 | + if(ip.indexOf(':') === -1) { |
90 | + $scope.ipVersion = 4; |
91 | + } else { |
92 | + $scope.ipVersion = 6; |
93 | + } |
94 | + } |
95 | + |
96 | + // Sort for IP address. |
97 | + $scope.ipSort = function(ipAddress) { |
98 | + if($scope.ipVersion === 4) { |
99 | + return ConverterService.ipv4ToInteger(ipAddress.ip); |
100 | + } else { |
101 | + return ConverterService.ipv6Expand(ipAddress.ip); |
102 | + } |
103 | + }; |
104 | + |
105 | + // Set default predicate to the ipSort function. |
106 | + $scope.predicate = $scope.ipSort; |
107 | + |
108 | + // Return the name of the allocation type. |
109 | + $scope.getAllocType = function(allocType) { |
110 | + var str = ALLOC_TYPES[allocType]; |
111 | + if(angular.isString(str)) { |
112 | + return str; |
113 | + } else { |
114 | + return "Unknown"; |
115 | + } |
116 | + }; |
117 | + |
118 | + // Sort based on the name of the allocation type. |
119 | + $scope.allocTypeSort = function(ipAddress) { |
120 | + return $scope.getAllocType(ipAddress.alloc_type); |
121 | + }; |
122 | + |
123 | + // Return the name of the node type. |
124 | + $scope.getNodeType = function(nodeType) { |
125 | + var str = NODE_TYPES[nodeType]; |
126 | + if(angular.isString(str)) { |
127 | + return str; |
128 | + } else { |
129 | + return "Unknown"; |
130 | + } |
131 | + }; |
132 | + |
133 | + // Sort based on the node type string. |
134 | + $scope.nodeTypeSort = function(ipAddress) { |
135 | + return $scope.getNodeType(ipAddress.node_summary.node_type); |
136 | + }; |
137 | + |
138 | + // Sort based on the owner name. |
139 | + $scope.ownerSort = function(ipAddress) { |
140 | + var owner = ipAddress.user; |
141 | + if(angular.isString(owner) && owner.length > 0) { |
142 | + return owner; |
143 | + } else { |
144 | + return "MAAS"; |
145 | + } |
146 | + }; |
147 | + |
148 | + // Called to change the sort order of the IP table. |
149 | + $scope.sortIPTable = function(predicate) { |
150 | + $scope.predicate = predicate; |
151 | + $scope.reverse = !$scope.reverse; |
152 | + }; |
153 | + |
154 | + // Return the name of the VLAN. |
155 | $scope.getVLANName = function(vlan) { |
156 | return VLANsManager.getName(vlan); |
157 | }; |
158 | @@ -179,6 +264,7 @@ |
159 | }; |
160 | $scope.$watch("subnet.fabric", updateFabric); |
161 | $scope.$watch("subnet.vlan", updateFabric); |
162 | + $scope.$watch("subnet.cidr", updateIPVersion); |
163 | } |
164 | |
165 | // Load all the required managers. |
166 | |
167 | === modified file 'src/maasserver/static/js/angular/controllers/tests/test_subnet_details.js' |
168 | --- src/maasserver/static/js/angular/controllers/tests/test_subnet_details.js 2016-06-13 14:21:20 +0000 |
169 | +++ src/maasserver/static/js/angular/controllers/tests/test_subnet_details.js 2016-06-16 14:50:25 +0000 |
170 | @@ -72,6 +72,7 @@ |
171 | // Load any injected managers and services. |
172 | var SubnetsManager, IPRangesManager, SpacesManager, VLANsManager; |
173 | var FabricsManager, UsersManager, HelperService, ErrorService; |
174 | + var ConverterService; |
175 | beforeEach(inject(function($injector) { |
176 | SubnetsManager = $injector.get("SubnetsManager"); |
177 | IPRangesManager = $injector.get("IPRangesManager"); |
178 | @@ -81,6 +82,7 @@ |
179 | UsersManager = $injector.get("UsersManager"); |
180 | ManagerHelperService = $injector.get("ManagerHelperService"); |
181 | ErrorService = $injector.get("ErrorService"); |
182 | + ConverterService = $injector.get("ConverterService"); |
183 | })); |
184 | |
185 | var fabric, vlan, space, subnet; |
186 | @@ -209,6 +211,158 @@ |
187 | expect($rootScope.title).toBe(subnet.cidr + " (" + subnet.name + ")"); |
188 | }); |
189 | |
190 | + describe("ipSort", function() { |
191 | + |
192 | + it("calls ipv4ToInteger when ipVersion == 4", function() { |
193 | + var controller = makeControllerResolveSetActiveItem(); |
194 | + $scope.ipVersion = 4; |
195 | + var expected = {}; |
196 | + spyOn(ConverterService, "ipv4ToInteger").and.returnValue(expected); |
197 | + var ipAddress = { |
198 | + ip: {} |
199 | + }; |
200 | + var observed = $scope.ipSort(ipAddress); |
201 | + expect(ConverterService.ipv4ToInteger).toHaveBeenCalledWith( |
202 | + ipAddress.ip); |
203 | + expect(observed).toBe(expected); |
204 | + }); |
205 | + |
206 | + it("calls ipv6Expand when ipVersion == 6", function() { |
207 | + var controller = makeControllerResolveSetActiveItem(); |
208 | + $scope.ipVersion = 6; |
209 | + var expected = {}; |
210 | + spyOn(ConverterService, "ipv6Expand").and.returnValue(expected); |
211 | + var ipAddress = { |
212 | + ip: {} |
213 | + }; |
214 | + var observed = $scope.ipSort(ipAddress); |
215 | + expect(ConverterService.ipv6Expand).toHaveBeenCalledWith( |
216 | + ipAddress.ip); |
217 | + expect(observed).toBe(expected); |
218 | + }); |
219 | + |
220 | + it("is predicate default", function() { |
221 | + var controller = makeControllerResolveSetActiveItem(); |
222 | + expect($scope.predicate).toBe($scope.ipSort); |
223 | + }); |
224 | + }); |
225 | + |
226 | + describe("getAllocType", function() { |
227 | + |
228 | + var scenarios = { |
229 | + 0: 'Automatic', |
230 | + 1: 'Static', |
231 | + 4: 'User reserved', |
232 | + 5: 'DHCP', |
233 | + 6: 'Observed', |
234 | + 7: 'Unknown' |
235 | + }; |
236 | + |
237 | + angular.forEach(scenarios, function(expected, allocType) { |
238 | + it("allocType( " + allocType + ") = " + expected, function() { |
239 | + var controller = makeControllerResolveSetActiveItem(); |
240 | + expect($scope.getAllocType(allocType)).toBe(expected); |
241 | + }); |
242 | + }); |
243 | + }); |
244 | + |
245 | + describe("allocTypeSort", function() { |
246 | + |
247 | + it("calls getAllocType", function() { |
248 | + var controller = makeControllerResolveSetActiveItem(); |
249 | + var expected = {}; |
250 | + spyOn($scope, "getAllocType").and.returnValue(expected); |
251 | + var ipAddress = { |
252 | + alloc_type: {} |
253 | + }; |
254 | + var observed = $scope.allocTypeSort(ipAddress); |
255 | + expect($scope.getAllocType).toHaveBeenCalledWith( |
256 | + ipAddress.alloc_type); |
257 | + expect(observed).toBe(expected); |
258 | + }); |
259 | + }); |
260 | + |
261 | + describe("getNodeType", function() { |
262 | + |
263 | + var scenarios = { |
264 | + 0: 'Machine', |
265 | + 1: 'Device', |
266 | + 2: 'Rack controller', |
267 | + 3: 'Region controller', |
268 | + 4: 'Rack and region controller', |
269 | + 5: 'Unknown' |
270 | + }; |
271 | + |
272 | + angular.forEach(scenarios, function(expected, nodeType) { |
273 | + it("nodeType( " + nodeType + ") = " + expected, function() { |
274 | + var controller = makeControllerResolveSetActiveItem(); |
275 | + expect($scope.getNodeType(nodeType)).toBe(expected); |
276 | + }); |
277 | + }); |
278 | + }); |
279 | + |
280 | + describe("nodeTypeSort", function() { |
281 | + |
282 | + it("calls getNodeType", function() { |
283 | + var controller = makeControllerResolveSetActiveItem(); |
284 | + var expected = {}; |
285 | + spyOn($scope, "getNodeType").and.returnValue(expected); |
286 | + var ipAddress = { |
287 | + node_summary: { |
288 | + node_type: {} |
289 | + } |
290 | + }; |
291 | + var observed = $scope.nodeTypeSort(ipAddress); |
292 | + expect($scope.getNodeType).toHaveBeenCalledWith( |
293 | + ipAddress.node_summary.node_type); |
294 | + expect(observed).toBe(expected); |
295 | + }); |
296 | + }); |
297 | + |
298 | + describe("ownerSort", function() { |
299 | + |
300 | + it("returns owner", function() { |
301 | + var controller = makeControllerResolveSetActiveItem(); |
302 | + var ipAddress = { |
303 | + user: makeName("owner") |
304 | + }; |
305 | + var observed = $scope.ownerSort(ipAddress); |
306 | + expect(observed).toBe(ipAddress.user); |
307 | + }); |
308 | + |
309 | + it("returns MAAS for empty string", function() { |
310 | + var controller = makeControllerResolveSetActiveItem(); |
311 | + var ipAddress = { |
312 | + user: "" |
313 | + }; |
314 | + var observed = $scope.ownerSort(ipAddress); |
315 | + expect(observed).toBe("MAAS"); |
316 | + }); |
317 | + |
318 | + it("returns MAAS for null", function() { |
319 | + var controller = makeControllerResolveSetActiveItem(); |
320 | + var ipAddress = { |
321 | + user: null |
322 | + }; |
323 | + var observed = $scope.ownerSort(ipAddress); |
324 | + expect(observed).toBe("MAAS"); |
325 | + }); |
326 | + }); |
327 | + |
328 | + describe("sortIPTable", function() { |
329 | + |
330 | + it("sets predicate and inverts reverse", function() { |
331 | + var controller = makeControllerResolveSetActiveItem(); |
332 | + $scope.reverse = true; |
333 | + var predicate = {}; |
334 | + $scope.sortIPTable(predicate); |
335 | + expect($scope.predicate).toBe(predicate); |
336 | + expect($scope.reverse).toBe(false); |
337 | + $scope.sortIPTable(predicate); |
338 | + expect($scope.reverse).toBe(true); |
339 | + }); |
340 | + }); |
341 | + |
342 | describe("deleteButton", function() { |
343 | |
344 | it("confirms delete", function() { |
345 | |
346 | === modified file 'src/maasserver/static/js/angular/services/converter.js' |
347 | --- src/maasserver/static/js/angular/services/converter.js 2016-03-28 13:54:47 +0000 |
348 | +++ src/maasserver/static/js/angular/services/converter.js 2016-06-16 14:50:25 +0000 |
349 | @@ -86,4 +86,59 @@ |
350 | this.roundByBlockSize = function(bytes, block_size) { |
351 | return block_size * Math.floor(bytes / block_size); |
352 | }; |
353 | + |
354 | + // Convert string ipv4 address into octets array. |
355 | + this.ipv4ToOctets = function(ipAddress) { |
356 | + var parts = ipAddress.split('.'); |
357 | + var octets = []; |
358 | + angular.forEach(parts, function(part) { |
359 | + octets.push(parseInt(part, 10)); |
360 | + }); |
361 | + return octets; |
362 | + }; |
363 | + |
364 | + // Convert string ipv4 address into integer. |
365 | + this.ipv4ToInteger = function(ipAddress) { |
366 | + var octets = this.ipv4ToOctets(ipAddress); |
367 | + return ( |
368 | + (octets[0] * Math.pow(256,3)) + |
369 | + (octets[1] * Math.pow(256,2)) + |
370 | + (octets[2] * 256) + octets[3]); |
371 | + }; |
372 | + |
373 | + // Convert ipv6 address to a full ipv6 address, removing the |
374 | + // '::' shortcut and padding each group with zeros. |
375 | + this.ipv6Expand = function(ipAddress) { |
376 | + var i, expandedAddress = ipAddress; |
377 | + if(expandedAddress.indexOf("::") !== -1) { |
378 | + // '::' is present so replace it with the required |
379 | + // number of '0000:' based on its location in the string. |
380 | + var split = ipAddress.split("::"); |
381 | + var groups = 0; |
382 | + for(i = 0; i < split.length; i++) { |
383 | + groups += split[i].split(":").length; |
384 | + } |
385 | + expandedAddress = split[0] + ":"; |
386 | + for(i = 0; i < 8 - groups; i++) { |
387 | + expandedAddress += "0000:"; |
388 | + } |
389 | + expandedAddress += split[1]; |
390 | + } |
391 | + // Pad the output of each part with zeros. |
392 | + var output = [], parts = expandedAddress.split(":"); |
393 | + angular.forEach(parts, function(part) { |
394 | + output.push("0000".substr(part.length) + part); |
395 | + }); |
396 | + return output.join(":"); |
397 | + }; |
398 | + |
399 | + // Convert string ipv6 into groups array. |
400 | + this.ipv6ToGroups = function(ipAddress) { |
401 | + var groups = []; |
402 | + var parts = this.ipv6Expand(ipAddress).split(":"); |
403 | + angular.forEach(parts, function(part) { |
404 | + groups.push(parseInt(part, 16)); |
405 | + }); |
406 | + return groups; |
407 | + }; |
408 | }); |
409 | |
410 | === modified file 'src/maasserver/static/js/angular/services/tests/test_converter.js' |
411 | --- src/maasserver/static/js/angular/services/tests/test_converter.js 2016-03-28 13:54:47 +0000 |
412 | +++ src/maasserver/static/js/angular/services/tests/test_converter.js 2016-06-16 14:50:25 +0000 |
413 | @@ -201,4 +201,108 @@ |
414 | 1024 * 1024 * 1024); |
415 | }); |
416 | }); |
417 | + |
418 | + describe("ipv4ToOctets", function() { |
419 | + |
420 | + var scenarios = [ |
421 | + { |
422 | + input: "192.168.1.1", |
423 | + output: [192,168,1,1] |
424 | + }, |
425 | + { |
426 | + input: "172.16.1.1", |
427 | + output: [172,16,1,1] |
428 | + }, |
429 | + { |
430 | + input: "10.1.1.1", |
431 | + output: [10,1,1,1] |
432 | + } |
433 | + ]; |
434 | + |
435 | + angular.forEach(scenarios, function(scenario) { |
436 | + it("converts: " + scenario.input, function() { |
437 | + var result = ConverterService.ipv4ToOctets(scenario.input); |
438 | + expect(result).toEqual(scenario.output); |
439 | + }); |
440 | + }); |
441 | + }); |
442 | + |
443 | + describe("ipv4ToInteger", function() { |
444 | + |
445 | + var scenarios = [ |
446 | + { |
447 | + input: "192.168.1.1", |
448 | + output: 3232235777 |
449 | + }, |
450 | + { |
451 | + input: "172.16.1.1", |
452 | + output: 2886729985 |
453 | + }, |
454 | + { |
455 | + input: "10.1.1.1", |
456 | + output: 167837953 |
457 | + } |
458 | + ]; |
459 | + |
460 | + angular.forEach(scenarios, function(scenario) { |
461 | + it("converts: " + scenario.input, function() { |
462 | + var result = ConverterService.ipv4ToInteger(scenario.input); |
463 | + expect(result).toEqual(scenario.output); |
464 | + }); |
465 | + }); |
466 | + }); |
467 | + |
468 | + describe("ipv6Expand", function() { |
469 | + |
470 | + var scenarios = [ |
471 | + { |
472 | + input: "::1", |
473 | + output: "0000:0000:0000:0000:0000:0000:0000:0001" |
474 | + }, |
475 | + { |
476 | + input: "2001:db8::1", |
477 | + output: "2001:0db8:0000:0000:0000:0000:0000:0001" |
478 | + }, |
479 | + { |
480 | + input: "2001:db8:1::1", |
481 | + output: "2001:0db8:0001:0000:0000:0000:0000:0001" |
482 | + }, |
483 | + { |
484 | + input: "2001:db8::", |
485 | + output: "2001:0db8:0000:0000:0000:0000:0000:0000" |
486 | + } |
487 | + ]; |
488 | + |
489 | + angular.forEach(scenarios, function(scenario) { |
490 | + it("expands: " + scenario.input, function() { |
491 | + var result = ConverterService.ipv6Expand(scenario.input); |
492 | + expect(result).toBe(scenario.output); |
493 | + }); |
494 | + }); |
495 | + }); |
496 | + |
497 | + describe("ipv6ToGroups", function() { |
498 | + |
499 | + var scenarios = [ |
500 | + { |
501 | + input: "::1", |
502 | + output: [0, 0, 0, 0, 0, 0, 0, 1] |
503 | + }, |
504 | + { |
505 | + input: "2001:db8::1", |
506 | + output: [8193, 3512, 0, 0, 0, 0, 0, 1] |
507 | + }, |
508 | + { |
509 | + input: "2001:db8:1::1", |
510 | + output: [8193, 3512, 1, 0, 0, 0, 0, 1] |
511 | + } |
512 | + ]; |
513 | + |
514 | + angular.forEach(scenarios, function(scenario) { |
515 | + it("converts: " + scenario.input, function() { |
516 | + var result = ConverterService.ipv6ToGroups(scenario.input); |
517 | + expect(result).toEqual(scenario.output); |
518 | + }); |
519 | + }); |
520 | + }); |
521 | }); |
522 | |
523 | === modified file 'src/maasserver/static/js/angular/services/validation.js' |
524 | --- src/maasserver/static/js/angular/services/validation.js 2016-03-28 13:54:47 +0000 |
525 | +++ src/maasserver/static/js/angular/services/validation.js 2016-06-16 14:50:25 +0000 |
526 | @@ -6,7 +6,8 @@ |
527 | * Used by controllers to validate user inputs. |
528 | */ |
529 | |
530 | -angular.module('MAAS').service('ValidationService', function() { |
531 | +angular.module('MAAS').service('ValidationService', [ |
532 | + 'ConverterService', function(ConverterService) { |
533 | |
534 | // Pattern that matches a domainname. |
535 | // XXX 2016-02-24 lamont: This also matches "example.com.", |
536 | @@ -50,47 +51,6 @@ |
537 | return true; |
538 | } |
539 | |
540 | - // Convert string ipv4 address into octets array. |
541 | - function ipv4ToOctets(ipAddress) { |
542 | - var parts = ipAddress.split('.'); |
543 | - var octets = []; |
544 | - angular.forEach(parts, function(part) { |
545 | - octets.push(parseInt(part, 10)); |
546 | - }); |
547 | - return octets; |
548 | - } |
549 | - |
550 | - // Convert ipv6 address to a full ipv6 address, removing the |
551 | - // '::' shortcut. |
552 | - function ipv6Expand(ipAddress) { |
553 | - var i, expandedAddress = ipAddress; |
554 | - if(expandedAddress.indexOf("::") !== -1) { |
555 | - // '::' is present so replace it with the required |
556 | - // number of '0000:' based on its location in the string. |
557 | - var split = ipAddress.split("::"); |
558 | - var groups = 0; |
559 | - for(i = 0; i < split.length; i++) { |
560 | - groups += split[i].split(":").length; |
561 | - } |
562 | - expandedAddress = split[0] + ":"; |
563 | - for(i = 0; i < 8 - groups; i++) { |
564 | - expandedAddress += "0000:"; |
565 | - } |
566 | - expandedAddress += split[1]; |
567 | - } |
568 | - return expandedAddress; |
569 | - } |
570 | - |
571 | - // Convert string ipv6 into octets array. |
572 | - function ipv6ToOctets(ipAddress) { |
573 | - var octets = []; |
574 | - var parts = ipv6Expand(ipAddress).split(":"); |
575 | - angular.forEach(parts, function(part) { |
576 | - octets.push(parseInt(part, 16)); |
577 | - }); |
578 | - return octets; |
579 | - } |
580 | - |
581 | // Return true if the domainname is valid, false otherwise. |
582 | this.validateDomainName = function(domainname) { |
583 | // Invalid if the domain is not a string, empty, or more than |
584 | @@ -140,8 +100,8 @@ |
585 | ipAddress.indexOf(':') === -1) { |
586 | return false; |
587 | } |
588 | - var expandedAddress = ipv6Expand(ipAddress); |
589 | - var octets = ipv6ToOctets(expandedAddress); |
590 | + var expandedAddress = ConverterService.ipv6Expand(ipAddress); |
591 | + var octets = ConverterService.ipv6ToGroups(expandedAddress); |
592 | if(octets.length !== 8) { |
593 | return false; |
594 | } |
595 | @@ -180,14 +140,14 @@ |
596 | if(this.validateIPv4(ipAddress) && |
597 | this.validateIPv4(networkAddress)) { |
598 | return cidrMatcher( |
599 | - ipv4ToOctets(ipAddress), |
600 | - ipv4ToOctets(networkAddress), |
601 | + ConverterService.ipv4ToOctets(ipAddress), |
602 | + ConverterService.ipv4ToOctets(networkAddress), |
603 | 8, cidrBits); |
604 | } else if(this.validateIPv6(ipAddress) && |
605 | this.validateIPv6(networkAddress)) { |
606 | return cidrMatcher( |
607 | - ipv6ToOctets(ipAddress), |
608 | - ipv6ToOctets(networkAddress), |
609 | + ConverterService.ipv6ToGroups(ipAddress), |
610 | + ConverterService.ipv6ToGroups(networkAddress), |
611 | 16, cidrBits); |
612 | } |
613 | return false; |
614 | @@ -210,9 +170,9 @@ |
615 | |
616 | // Check that each octet is of the ip address is more or equal |
617 | // to the low address and less or equal to the high address. |
618 | - ipOctets = ipv4ToOctets(ipAddress); |
619 | - lowOctets = ipv4ToOctets(lowAddress); |
620 | - highOctets = ipv4ToOctets(highAddress); |
621 | + ipOctets = ConverterService.ipv4ToOctets(ipAddress); |
622 | + lowOctets = ConverterService.ipv4ToOctets(lowAddress); |
623 | + highOctets = ConverterService.ipv4ToOctets(highAddress); |
624 | for(i = 0; i < 4; i++) { |
625 | if(ipOctets[i] > highOctets[i] || |
626 | ipOctets[i] < lowOctets[i]) { |
627 | @@ -226,9 +186,9 @@ |
628 | |
629 | // Check that each octet is of the ip address is more or equal |
630 | // to the low address and less or equal to the high address. |
631 | - ipOctets = ipv6ToOctets(ipAddress); |
632 | - lowOctets = ipv6ToOctets(lowAddress); |
633 | - highOctets = ipv6ToOctets(highAddress); |
634 | + ipOctets = ConverterService.ipv6ToGroups(ipAddress); |
635 | + lowOctets = ConverterService.ipv6ToGroups(lowAddress); |
636 | + highOctets = ConverterService.ipv6ToGroups(highAddress); |
637 | for(i = 0; i < 8; i++) { |
638 | if(ipOctets[i] > highOctets[i] || |
639 | ipOctets[i] < lowOctets[i]) { |
640 | @@ -239,4 +199,4 @@ |
641 | } |
642 | return false; |
643 | }; |
644 | - }); |
645 | + }]); |
646 | |
647 | === modified file 'src/maasserver/static/partials/subnet-details.html' |
648 | --- src/maasserver/static/partials/subnet-details.html 2016-06-09 20:08:35 +0000 |
649 | +++ src/maasserver/static/partials/subnet-details.html 2016-06-16 14:50:25 +0000 |
650 | @@ -250,36 +250,33 @@ |
651 | <table class="table-listing"> |
652 | <thead> |
653 | <tr class="table-listing__row"> |
654 | - <th class="table-listing__header table-col--20">IP Address</th> |
655 | - <th class="table-listing__header table-col--10">Type</th> |
656 | - <th class="table-listing__header table-col--15">Node</th> |
657 | - <th class="table-listing__header table-col--10">Interface</th> |
658 | - <th class="table-listing__header table-col--10">Usage</th> |
659 | - <th class="table-listing__header table-col--10">Owner</th> |
660 | - <th class="table-listing__header table-col--25">Last seen</th> |
661 | - <!-- XXX mpontillo need data for this --> |
662 | - <!-- |
663 | - <th class="table-listing__header table-col--25" colspan="2"> |
664 | - <a class="table-listing__header-link" href="#">Purpose</a> |
665 | - <span class="divide"></span> |
666 | - <a class="table-listing__header-link active" href="#">Last seen</a> |
667 | - <span class="divide"></span> |
668 | - <a class="table-listing__header-link" href="#">Detected</a> |
669 | - </th> |
670 | - --> |
671 | + <th class="table-listing__header table-col--20"> |
672 | + <a href="" data-ng-click="sortIPTable(ipSort)" data-ng-class="{sort: predicate === ipSort, 'sort-asc': reverse === false, 'sort-desc': reverse === true}">IP Address</a> |
673 | + </th> |
674 | + <th class="table-listing__header table-col--10"> |
675 | + <a href="" data-ng-click="sortIPTable(allocTypeSort)" data-ng-class="{sort: predicate === allocTypeSort, 'sort-asc': reverse === false, 'sort-desc': reverse === true}">Type</a> |
676 | + </th> |
677 | + <th class="table-listing__header table-col--15"> |
678 | + <a href="" data-ng-click="sortIPTable('node_summary.hostname')" data-ng-class="{sort: predicate === 'node_summary.hostname', 'sort-asc': reverse === false, 'sort-desc': reverse === true}">Node</a> |
679 | + </th> |
680 | + <th class="table-listing__header table-col--10"> |
681 | + <a href="" data-ng-click="sortIPTable('node_summary.via')" data-ng-class="{sort: predicate === 'node_summary.via', 'sort-asc': reverse === false, 'sort-desc': reverse === true}">Interface</a> |
682 | + </th> |
683 | + <th class="table-listing__header table-col--10"> |
684 | + <a href="" data-ng-click="sortIPTable(nodeTypeSort)" data-ng-class="{sort: predicate === nodeTypeSort, 'sort-asc': reverse === false, 'sort-desc': reverse === true}">Usage</a> |
685 | + </th> |
686 | + <th class="table-listing__header table-col--10"> |
687 | + <a href="" data-ng-click="sortIPTable(ownerSort)" data-ng-class="{sort: predicate === ownerSort, 'sort-asc': reverse === false, 'sort-desc': reverse === true}">Owner</a> |
688 | + </th> |
689 | + <th class="table-listing__header table-col--25"> |
690 | + <a href="" data-ng-click="sortIPTable('updated')" data-ng-class="{sort: predicate === 'updated', 'sort-asc': reverse === false, 'sort-desc': reverse === true}">Last seen</a> |
691 | + </th> |
692 | </tr> |
693 | </thead> |
694 | <tbody> |
695 | - <tr data-ng-repeat="ip in subnet.ip_addresses"> |
696 | + <tr data-ng-repeat="ip in subnet.ip_addresses | orderBy:predicate:reverse track by ip.ip"> |
697 | <td class="table-col--20">{$ ip.ip $}</td> |
698 | - <td class="table-col--10" data-ng-switch="ip.alloc_type"> |
699 | - <span data-ng-switch-when="0">Automatic</span> |
700 | - <span data-ng-switch-when="1">Static</span> |
701 | - <span data-ng-switch-when="4">User reserved</span> |
702 | - <span data-ng-switch-when="5">DHCP</span> |
703 | - <span data-ng-switch-when="6">Observed</span> |
704 | - <span data-ng-switch-default>Unknown</span> |
705 | - </td> |
706 | + <td class="table-col--10">{$ getAllocType(ip.alloc_type) $}</td> |
707 | <td class="table-col--15" data-ng-switch="ip.node_summary.node_type"> |
708 | <span data-ng-switch-when="0"><a href="#/node/{$ ip.node_summary.system_id $}">{$ ip.node_summary.hostname $}</a></span> |
709 | <span data-ng-switch-when="1">{$ ip.node_summary.hostname $}</span> |
710 | @@ -295,14 +292,7 @@ |
711 | <span data-ng-switch-when="4">{$ ip.node_summary.via $}</span> |
712 | <span data-ng-switch-default>Unknown</span> |
713 | </td> |
714 | - <td class="table-col--10" data-ng-switch="ip.node_summary.node_type"> |
715 | - <span data-ng-switch-when="0">Machine</span> |
716 | - <span data-ng-switch-when="1">Device</span> |
717 | - <span data-ng-switch-when="2">Rack controller</span> |
718 | - <span data-ng-switch-when="3">Region controller</span> |
719 | - <span data-ng-switch-when="4">Rack and region controller</span> |
720 | - <span data-ng-switch-default>Unknown</span> |
721 | - </td> |
722 | + <td class="table-col--10">{$ getNodeType(ip.node_summary.node_type) $}</td> |
723 | <td class="table-col--10">{$ ip.user ? ip.user : "MAAS" $}</td> |
724 | <td class="table-col--25"> |
725 | <time>{$ ip.updated $}</time> |
LGTM, might want to move some display strings to a central location, comments below.