Merge lp:~lamont/maas/raid10 into lp:~maas-committers/maas/trunk

Proposed by LaMont Jones
Status: Merged
Approved by: LaMont Jones
Approved revision: no longer in the source branch.
Merged at revision: 4432
Proposed branch: lp:~lamont/maas/raid10
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 533 lines (+275/-8)
9 files modified
src/maasserver/api/tests/test_raid.py (+74/-3)
src/maasserver/enum.py (+5/-0)
src/maasserver/models/filesystemgroup.py (+9/-0)
src/maasserver/models/tests/test_filesystemgroup.py (+119/-3)
src/maasserver/preseed_storage.py (+1/-0)
src/maasserver/static/js/angular/controllers/node_details_storage.js (+9/-0)
src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js (+45/-2)
src/maasserver/testing/factory.py (+12/-0)
src/maasserver/tests/test_forms_raid.py (+1/-0)
To merge this branch: bzr merge lp:~lamont/maas/raid10
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+276058@code.launchpad.net

Commit message

Add RAID 10 support to storage.

Description of the change

Add RAID 10 support to storage.

To post a comment you must log in.
Revision history for this message
Blake Rouse (blake-rouse) wrote :

At quick glance looks to be missing unit tests for the JS.

review: Needs Fixing
Revision history for this message
LaMont Jones (lamont) wrote :

> At quick glance looks to be missing unit tests for the JS.

Good catch. Added those, and updated them to fail if someone adds another raid type without fixing them.

Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks really good!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/api/tests/test_raid.py'
--- src/maasserver/api/tests/test_raid.py 2015-09-24 16:22:12 +0000
+++ src/maasserver/api/tests/test_raid.py 2015-10-29 13:27:52 +0000
@@ -97,6 +97,8 @@
97 node=node, group_type=FILESYSTEM_GROUP_TYPE.RAID_5),97 node=node, group_type=FILESYSTEM_GROUP_TYPE.RAID_5),
98 factory.make_FilesystemGroup(98 factory.make_FilesystemGroup(
99 node=node, group_type=FILESYSTEM_GROUP_TYPE.RAID_6),99 node=node, group_type=FILESYSTEM_GROUP_TYPE.RAID_6),
100 factory.make_FilesystemGroup(
101 node=node, group_type=FILESYSTEM_GROUP_TYPE.RAID_10),
100 ]102 ]
101 # Not RAID. Should not be in the output.103 # Not RAID. Should not be in the output.
102 for _ in range(3):104 for _ in range(3):
@@ -419,7 +421,7 @@
419 bds = [421 bds = [
420 factory.make_PhysicalBlockDevice(node=node, size=10 * 1000 ** 4)422 factory.make_PhysicalBlockDevice(node=node, size=10 * 1000 ** 4)
421 for i in range(10)423 for i in range(10)
422 ]424 ]
423 for bd in bds[5:]:425 for bd in bds[5:]:
424 factory.make_PartitionTable(block_device=bd)426 factory.make_PartitionTable(block_device=bd)
425 for bd in bds[5:]:427 for bd in bds[5:]:
@@ -446,7 +448,7 @@
446448
447 parsed_device = json.loads(response.content)449 parsed_device = json.loads(response.content)
448 (parsed_block_devices, parsed_partitions,450 (parsed_block_devices, parsed_partitions,
449 parsed_block_device_spares, parsed_partition_spares) = (451 parsed_block_device_spares, parsed_partition_spares) = (
450 get_devices_from_raid(parsed_device))452 get_devices_from_raid(parsed_device))
451 # Size is equivalent to 6 devices of 9 TB each.453 # Size is equivalent to 6 devices of 9 TB each.
452 self.assertEqual(454 self.assertEqual(
@@ -457,6 +459,53 @@
457 self.assertItemsEqual(spare_devices, parsed_block_device_spares)459 self.assertItemsEqual(spare_devices, parsed_block_device_spares)
458 self.assertItemsEqual(spare_partitions, parsed_partition_spares)460 self.assertItemsEqual(spare_partitions, parsed_partition_spares)
459461
462 def test_create_raid_10(self):
463 """Checks it's possible to create a RAID 10 using 4 raw
464 devices, 4 partitions, one spare device and one spare partition."""
465 self.become_admin()
466 node = factory.make_Node(status=NODE_STATUS.READY)
467 # Add 10 10TB physical block devices to the node.
468 bds = [
469 factory.make_PhysicalBlockDevice(node=node, size=10 * 1000 ** 4)
470 for i in range(10)
471 ]
472 for bd in bds[5:]:
473 factory.make_PartitionTable(block_device=bd)
474 for bd in bds[5:]:
475 bd.get_partitiontable().add_partition(size=1000 ** 4)
476 large_partitions = [bd.get_partitiontable().add_partition()
477 for bd in bds[5:]]
478 uuid4 = unicode(uuid.uuid4())
479 uri = get_raid_devices_uri(node)
480 block_devices = [bd.id for bd in bds[1:]
481 if bd.get_partitiontable() is None]
482 partitions = [lp.id for lp in large_partitions[1:]]
483 spare_devices = [bds[0].id]
484 spare_partitions = [large_partitions[0].id]
485 response = self.client.post(uri, {
486 'name': 'md0',
487 'uuid': uuid4,
488 'level': FILESYSTEM_GROUP_TYPE.RAID_10,
489 'block_devices': block_devices,
490 'partitions': partitions,
491 'spare_devices': spare_devices,
492 'spare_partitions': spare_partitions,
493 })
494 self.assertEqual(httplib.OK, response.status_code, response.content)
495
496 parsed_device = json.loads(response.content)
497 (parsed_block_devices, parsed_partitions,
498 parsed_block_device_spares, parsed_partition_spares) = (
499 get_devices_from_raid(parsed_device))
500 # Size is equivalent to 4 devices of 9 TB each.
501 self.assertEqual(
502 4 * ((9 * 1000 ** 4) - PARTITION_TABLE_EXTRA_SPACE),
503 parsed_device['size'])
504 self.assertItemsEqual(block_devices, parsed_block_devices)
505 self.assertItemsEqual(partitions, parsed_partitions)
506 self.assertItemsEqual(spare_devices, parsed_block_device_spares)
507 self.assertItemsEqual(spare_partitions, parsed_partition_spares)
508
460 def test_create_raid_5_with_2_elements_fails(self):509 def test_create_raid_5_with_2_elements_fails(self):
461 self.become_admin()510 self.become_admin()
462 node = factory.make_Node(status=NODE_STATUS.READY)511 node = factory.make_Node(status=NODE_STATUS.READY)
@@ -486,13 +535,35 @@
486 bds = [535 bds = [
487 factory.make_PhysicalBlockDevice(node=node, size=10 * 1000 ** 4)536 factory.make_PhysicalBlockDevice(node=node, size=10 * 1000 ** 4)
488 for i in range(3)537 for i in range(3)
538 ]
539 uuid4 = unicode(uuid.uuid4())
540 uri = get_raid_devices_uri(node)
541 response = self.client.post(uri, {
542 'name': 'md0',
543 'uuid': uuid4,
544 'level': FILESYSTEM_GROUP_TYPE.RAID_6,
545 'block_devices': [bd.id for bd in bds],
546 'partitions': [],
547 'spare_devices': [],
548 'spare_partitions': [],
549 })
550 self.assertEqual(httplib.BAD_REQUEST, response.status_code,
551 response.content)
552
553 def test_create_raid_10_with_2_elements_fails(self):
554 self.become_admin()
555 node = factory.make_Node(status=NODE_STATUS.READY)
556 # Add 3 10TB physical block devices to the node.
557 bds = [
558 factory.make_PhysicalBlockDevice(node=node, size=10 * 1000 ** 4)
559 for i in range(2)
489 ]560 ]
490 uuid4 = unicode(uuid.uuid4())561 uuid4 = unicode(uuid.uuid4())
491 uri = get_raid_devices_uri(node)562 uri = get_raid_devices_uri(node)
492 response = self.client.post(uri, {563 response = self.client.post(uri, {
493 'name': 'md0',564 'name': 'md0',
494 'uuid': uuid4,565 'uuid': uuid4,
495 'level': FILESYSTEM_GROUP_TYPE.RAID_6,566 'level': FILESYSTEM_GROUP_TYPE.RAID_10,
496 'block_devices': [bd.id for bd in bds],567 'block_devices': [bd.id for bd in bds],
497 'partitions': [],568 'partitions': [],
498 'spare_devices': [],569 'spare_devices': [],
499570
=== modified file 'src/maasserver/enum.py'
--- src/maasserver/enum.py 2015-10-04 20:47:36 +0000
+++ src/maasserver/enum.py 2015-10-29 13:27:52 +0000
@@ -463,6 +463,9 @@
463 #: RAID level 6463 #: RAID level 6
464 RAID_6 = 'raid-6'464 RAID_6 = 'raid-6'
465465
466 #: RAID level 10
467 RAID_10 = 'raid-10'
468
466 #: Bcache469 #: Bcache
467 BCACHE = 'bcache'470 BCACHE = 'bcache'
468471
@@ -472,6 +475,7 @@
472 FILESYSTEM_GROUP_TYPE.RAID_1,475 FILESYSTEM_GROUP_TYPE.RAID_1,
473 FILESYSTEM_GROUP_TYPE.RAID_5,476 FILESYSTEM_GROUP_TYPE.RAID_5,
474 FILESYSTEM_GROUP_TYPE.RAID_6,477 FILESYSTEM_GROUP_TYPE.RAID_6,
478 FILESYSTEM_GROUP_TYPE.RAID_10,
475 ]479 ]
476480
477# Django choices for FILESYSTEM_GROUP_RAID_TYPES: sequence of tuples (key, UI481# Django choices for FILESYSTEM_GROUP_RAID_TYPES: sequence of tuples (key, UI
@@ -481,6 +485,7 @@
481 (FILESYSTEM_GROUP_TYPE.RAID_1, "RAID 1"),485 (FILESYSTEM_GROUP_TYPE.RAID_1, "RAID 1"),
482 (FILESYSTEM_GROUP_TYPE.RAID_5, "RAID 5"),486 (FILESYSTEM_GROUP_TYPE.RAID_5, "RAID 5"),
483 (FILESYSTEM_GROUP_TYPE.RAID_6, "RAID 6"),487 (FILESYSTEM_GROUP_TYPE.RAID_6, "RAID 6"),
488 (FILESYSTEM_GROUP_TYPE.RAID_10, "RAID 10"),
484 )489 )
485490
486# Django choices for FILESYSTEM_GROUP_TYPE: sequence of tuples (key, UI491# Django choices for FILESYSTEM_GROUP_TYPE: sequence of tuples (key, UI
487492
=== modified file 'src/maasserver/models/filesystemgroup.py'
--- src/maasserver/models/filesystemgroup.py 2015-10-09 04:35:47 +0000
+++ src/maasserver/models/filesystemgroup.py 2015-10-29 13:27:52 +0000
@@ -417,6 +417,8 @@
417 return min_size * (num_raid - 1)417 return min_size * (num_raid - 1)
418 elif self.group_type == FILESYSTEM_GROUP_TYPE.RAID_6:418 elif self.group_type == FILESYSTEM_GROUP_TYPE.RAID_6:
419 return min_size * (num_raid - 2)419 return min_size * (num_raid - 2)
420 elif self.group_type == FILESYSTEM_GROUP_TYPE.RAID_10:
421 return min_size * num_raid / 2
420 raise ValidationError("Unknown raid type: %s" % self.group_type)422 raise ValidationError("Unknown raid type: %s" % self.group_type)
421423
422 def get_bcache_backing_filesystem(self):424 def get_bcache_backing_filesystem(self):
@@ -583,6 +585,13 @@
583 raise ValidationError(585 raise ValidationError(
584 "RAID level 6 must have at least 4 raid devices and "586 "RAID level 6 must have at least 4 raid devices and "
585 "any number of spares.")587 "any number of spares.")
588 elif self.group_type == FILESYSTEM_GROUP_TYPE.RAID_10:
589 # RAID 10 must have at least 4 RAID filesystems, but can have
590 # spares.
591 if num_raid < 3:
592 raise ValidationError(
593 "RAID level 10 must have at least 3 raid devices and "
594 "any number of spares.")
586 num_raid_invalid = len([595 num_raid_invalid = len([
587 fstype596 fstype
588 for fstype in fstypes597 for fstype in fstypes
589598
=== modified file 'src/maasserver/models/tests/test_filesystemgroup.py'
--- src/maasserver/models/tests/test_filesystemgroup.py 2015-10-09 04:35:47 +0000
+++ src/maasserver/models/tests/test_filesystemgroup.py 2015-10-29 13:27:52 +0000
@@ -769,6 +769,36 @@
769 self.assertEquals(769 self.assertEquals(
770 small_size * (number_of_raid_devices - 1), fsgroup.get_size())770 small_size * (number_of_raid_devices - 1), fsgroup.get_size())
771771
772 def test_get_size_returns_correct_disk_size_for_raid_10(self):
773 node = factory.make_Node()
774 small_size = random.randint(
775 MIN_BLOCK_DEVICE_SIZE, MIN_BLOCK_DEVICE_SIZE ** 2)
776 other_size = random.randint(small_size + 1, small_size + (10 ** 5))
777 number_of_raid_devices = random.randint(3, 9)
778 filesystems = [
779 factory.make_Filesystem(
780 fstype=FILESYSTEM_TYPE.RAID,
781 block_device=factory.make_PhysicalBlockDevice(
782 node=node, size=small_size)),
783 ]
784 for _ in range(number_of_raid_devices):
785 filesystems.append(
786 factory.make_Filesystem(
787 fstype=FILESYSTEM_TYPE.RAID,
788 block_device=factory.make_PhysicalBlockDevice(
789 node=node, size=other_size)))
790 # Spares are ignored and not taken into calculation.
791 for _ in range(3):
792 filesystems.append(
793 factory.make_Filesystem(
794 fstype=FILESYSTEM_TYPE.RAID_SPARE,
795 block_device=factory.make_PhysicalBlockDevice(
796 node=node, size=other_size)))
797 fsgroup = factory.make_FilesystemGroup(
798 group_type=FILESYSTEM_GROUP_TYPE.RAID_10, filesystems=filesystems)
799 self.assertEquals(
800 small_size * (number_of_raid_devices + 1) / 2, fsgroup.get_size())
801
772 def test_get_size_returns_0_if_bcache_without_backing(self):802 def test_get_size_returns_0_if_bcache_without_backing(self):
773 fsgroup = FilesystemGroup(group_type=FILESYSTEM_GROUP_TYPE.BCACHE)803 fsgroup = FilesystemGroup(group_type=FILESYSTEM_GROUP_TYPE.BCACHE)
774 self.assertEquals(0, fsgroup.get_size())804 self.assertEquals(0, fsgroup.get_size())
@@ -1071,7 +1101,7 @@
1071 fstype=FILESYSTEM_TYPE.RAID,1101 fstype=FILESYSTEM_TYPE.RAID,
1072 block_device=factory.make_PhysicalBlockDevice(node=node))1102 block_device=factory.make_PhysicalBlockDevice(node=node))
1073 for _ in range(random.randint(1, 3))1103 for _ in range(random.randint(1, 3))
1074 ]1104 ]
1075 with ExpectedException(1105 with ExpectedException(
1076 ValidationError,1106 ValidationError,
1077 re.escape(1107 re.escape(
@@ -1088,7 +1118,7 @@
1088 fstype=FILESYSTEM_TYPE.RAID,1118 fstype=FILESYSTEM_TYPE.RAID,
1089 block_device=factory.make_PhysicalBlockDevice(node=node))1119 block_device=factory.make_PhysicalBlockDevice(node=node))
1090 for _ in range(random.randint(4, 10))1120 for _ in range(random.randint(4, 10))
1091 ]1121 ]
1092 for _ in range(random.randint(1, 5)):1122 for _ in range(random.randint(1, 5)):
1093 filesystems.append(1123 filesystems.append(
1094 factory.make_Filesystem(1124 factory.make_Filesystem(
@@ -1099,6 +1129,59 @@
1099 group_type=FILESYSTEM_GROUP_TYPE.RAID_6,1129 group_type=FILESYSTEM_GROUP_TYPE.RAID_6,
1100 filesystems=filesystems)1130 filesystems=filesystems)
11011131
1132 def test_cannot_save_raid_10_with_less_than_3_raid_devices(self):
1133 node = factory.make_Node()
1134 filesystems = [
1135 factory.make_Filesystem(
1136 fstype=FILESYSTEM_TYPE.RAID,
1137 block_device=factory.make_PhysicalBlockDevice(node=node))
1138 for _ in range(random.randint(1, 2))
1139 ]
1140 with ExpectedException(
1141 ValidationError,
1142 re.escape(
1143 "{'__all__': [u'RAID level 10 must have at least 3 raid "
1144 "devices and any number of spares.']}")):
1145 factory.make_FilesystemGroup(
1146 group_type=FILESYSTEM_GROUP_TYPE.RAID_10,
1147 filesystems=filesystems)
1148
1149 def test_can_save_raid_10_with_3_raid_devices_and_spares(self):
1150 node = factory.make_Node()
1151 filesystems = [
1152 factory.make_Filesystem(
1153 fstype=FILESYSTEM_TYPE.RAID,
1154 block_device=factory.make_PhysicalBlockDevice(node=node))
1155 for _ in range(3)
1156 ]
1157 for _ in range(random.randint(1, 5)):
1158 filesystems.append(
1159 factory.make_Filesystem(
1160 fstype=FILESYSTEM_TYPE.RAID_SPARE,
1161 block_device=factory.make_PhysicalBlockDevice(node=node)))
1162 # Test is that this does not raise an exception.
1163 factory.make_FilesystemGroup(
1164 group_type=FILESYSTEM_GROUP_TYPE.RAID_10,
1165 filesystems=filesystems)
1166
1167 def test_can_save_raid_10_with_4_or_more_raid_devices_and_spares(self):
1168 node = factory.make_Node()
1169 filesystems = [
1170 factory.make_Filesystem(
1171 fstype=FILESYSTEM_TYPE.RAID,
1172 block_device=factory.make_PhysicalBlockDevice(node=node))
1173 for _ in range(random.randint(4, 10))
1174 ]
1175 for _ in range(random.randint(1, 5)):
1176 filesystems.append(
1177 factory.make_Filesystem(
1178 fstype=FILESYSTEM_TYPE.RAID_SPARE,
1179 block_device=factory.make_PhysicalBlockDevice(node=node)))
1180 # Test is that this does not raise an exception.
1181 factory.make_FilesystemGroup(
1182 group_type=FILESYSTEM_GROUP_TYPE.RAID_10,
1183 filesystems=filesystems)
1184
1102 def test_cannot_save_bcache_without_cache_set(self):1185 def test_cannot_save_bcache_without_cache_set(self):
1103 node = factory.make_Node()1186 node = factory.make_Node()
1104 filesystems = [1187 filesystems = [
@@ -1319,6 +1402,10 @@
1319 (FILESYSTEM_GROUP_TYPE.RAID_6, {1402 (FILESYSTEM_GROUP_TYPE.RAID_6, {
1320 "group_type": FILESYSTEM_GROUP_TYPE.RAID_6,1403 "group_type": FILESYSTEM_GROUP_TYPE.RAID_6,
1321 "name": "RAID",1404 "name": "RAID",
1405 }),
1406 (FILESYSTEM_GROUP_TYPE.RAID_10, {
1407 "group_type": FILESYSTEM_GROUP_TYPE.RAID_10,
1408 "name": "RAID",
1322 }),1409 }),
1323 (FILESYSTEM_GROUP_TYPE.BCACHE, {1410 (FILESYSTEM_GROUP_TYPE.BCACHE, {
1324 "group_type": FILESYSTEM_GROUP_TYPE.BCACHE,1411 "group_type": FILESYSTEM_GROUP_TYPE.BCACHE,
@@ -1355,6 +1442,10 @@
1355 (FILESYSTEM_GROUP_TYPE.RAID_6, {1442 (FILESYSTEM_GROUP_TYPE.RAID_6, {
1356 "group_type": FILESYSTEM_GROUP_TYPE.RAID_6,1443 "group_type": FILESYSTEM_GROUP_TYPE.RAID_6,
1357 "prefix": "md",1444 "prefix": "md",
1445 }),
1446 (FILESYSTEM_GROUP_TYPE.RAID_10, {
1447 "group_type": FILESYSTEM_GROUP_TYPE.RAID_10,
1448 "prefix": "md",
1358 }),1449 }),
1359 (FILESYSTEM_GROUP_TYPE.BCACHE, {1450 (FILESYSTEM_GROUP_TYPE.BCACHE, {
1360 "group_type": FILESYSTEM_GROUP_TYPE.BCACHE,1451 "group_type": FILESYSTEM_GROUP_TYPE.BCACHE,
@@ -1391,6 +1482,10 @@
1391 (FILESYSTEM_GROUP_TYPE.RAID_6, {1482 (FILESYSTEM_GROUP_TYPE.RAID_6, {
1392 "group_type": FILESYSTEM_GROUP_TYPE.RAID_6,1483 "group_type": FILESYSTEM_GROUP_TYPE.RAID_6,
1393 "block_size": 512,1484 "block_size": 512,
1485 }),
1486 (FILESYSTEM_GROUP_TYPE.RAID_10, {
1487 "group_type": FILESYSTEM_GROUP_TYPE.RAID_10,
1488 "block_size": 512,
1394 }),1489 }),
1395 # For BCACHE see1490 # For BCACHE see
1396 # `test_get_virtual_block_device_block_size_returns_backing_for_bc`1491 # `test_get_virtual_block_device_block_size_returns_backing_for_bc`
@@ -1695,7 +1790,7 @@
1695 block_devices = [1790 block_devices = [
1696 factory.make_PhysicalBlockDevice(node=node)1791 factory.make_PhysicalBlockDevice(node=node)
1697 for _ in range(3)1792 for _ in range(3)
1698 ]1793 ]
1699 uuid = unicode(uuid4())1794 uuid = unicode(uuid4())
1700 with ExpectedException(1795 with ExpectedException(
1701 ValidationError,1796 ValidationError,
@@ -1711,6 +1806,27 @@
1711 spare_devices=[],1806 spare_devices=[],
1712 spare_partitions=[])1807 spare_partitions=[])
17131808
1809 def test_create_raid_10_with_2_elements_fails(self):
1810 node = factory.make_Node()
1811 block_devices = [
1812 factory.make_PhysicalBlockDevice(node=node)
1813 for _ in range(2)
1814 ]
1815 uuid = unicode(uuid4())
1816 with ExpectedException(
1817 ValidationError,
1818 re.escape(
1819 "{'__all__': [u'RAID level 10 must have at least 3 raid "
1820 "devices and any number of spares.']}")):
1821 RAID.objects.create_raid(
1822 name='md0',
1823 level=FILESYSTEM_GROUP_TYPE.RAID_10,
1824 uuid=uuid,
1825 block_devices=block_devices,
1826 partitions=[],
1827 spare_devices=[],
1828 spare_partitions=[])
1829
1714 def test_create_raid_with_block_device_from_other_node_fails(self):1830 def test_create_raid_with_block_device_from_other_node_fails(self):
1715 node1 = factory.make_Node()1831 node1 = factory.make_Node()
1716 node2 = factory.make_Node()1832 node2 = factory.make_Node()
17171833
=== modified file 'src/maasserver/preseed_storage.py'
--- src/maasserver/preseed_storage.py 2015-10-27 23:20:28 +0000
+++ src/maasserver/preseed_storage.py 2015-10-29 13:27:52 +0000
@@ -346,6 +346,7 @@
346 FILESYSTEM_GROUP_TYPE.RAID_1: 1,346 FILESYSTEM_GROUP_TYPE.RAID_1: 1,
347 FILESYSTEM_GROUP_TYPE.RAID_5: 5,347 FILESYSTEM_GROUP_TYPE.RAID_5: 5,
348 FILESYSTEM_GROUP_TYPE.RAID_6: 6,348 FILESYSTEM_GROUP_TYPE.RAID_6: 6,
349 FILESYSTEM_GROUP_TYPE.RAID_10: 10,
349 }350 }
350 return raid_levels[filesystem_group.group_type]351 return raid_levels[filesystem_group.group_type]
351352
352353
=== modified file 'src/maasserver/static/js/angular/controllers/node_details_storage.js'
--- src/maasserver/static/js/angular/controllers/node_details_storage.js 2015-10-23 16:34:24 +0000
+++ src/maasserver/static/js/angular/controllers/node_details_storage.js 2015-10-29 13:27:52 +0000
@@ -102,6 +102,15 @@
102 calculateSize: function(minSize, numDisks) {102 calculateSize: function(minSize, numDisks) {
103 return minSize * (numDisks - 2);103 return minSize * (numDisks - 2);
104 }104 }
105 },
106 {
107 level: "raid-10",
108 title: "RAID 10",
109 min_disks: 3,
110 allows_spares: true,
111 calculateSize: function(minSize, numDisks) {
112 return minSize * numDisks / 2;
113 }
105 }114 }
106 ];115 ];
107116
108117
=== modified file 'src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js'
--- src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js 2015-10-23 18:39:01 +0000
+++ src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js 2015-10-29 13:27:52 +0000
@@ -3024,9 +3024,10 @@
3024 var modes = $scope.getAvailableRAIDModes();3024 var modes = $scope.getAvailableRAIDModes();
3025 expect(modes[0].level).toEqual("raid-0");3025 expect(modes[0].level).toEqual("raid-0");
3026 expect(modes[1].level).toEqual("raid-1");3026 expect(modes[1].level).toEqual("raid-1");
3027 expect(modes.length).toEqual(2);
3027 });3028 });
30283029
3029 it("returns raid 0,1,5 for 3 disks", function() {3030 it("returns raid 0,1,5,10 for 3 disks", function() {
3030 var controller = makeController();3031 var controller = makeController();
3031 $scope.availableNew.devices = [{}, {}, {}];3032 $scope.availableNew.devices = [{}, {}, {}];
30323033
@@ -3034,9 +3035,11 @@
3034 expect(modes[0].level).toEqual("raid-0");3035 expect(modes[0].level).toEqual("raid-0");
3035 expect(modes[1].level).toEqual("raid-1");3036 expect(modes[1].level).toEqual("raid-1");
3036 expect(modes[2].level).toEqual("raid-5");3037 expect(modes[2].level).toEqual("raid-5");
3038 expect(modes[3].level).toEqual("raid-10");
3039 expect(modes.length).toEqual(4);
3037 });3040 });
30383041
3039 it("returns raid 0,1,5,6 for 4 disks", function() {3042 it("returns raid 0,1,5,6,10 for 4 disks", function() {
3040 var controller = makeController();3043 var controller = makeController();
3041 $scope.availableNew.devices = [{}, {}, {}, {}];3044 $scope.availableNew.devices = [{}, {}, {}, {}];
30423045
@@ -3045,6 +3048,8 @@
3045 expect(modes[1].level).toEqual("raid-1");3048 expect(modes[1].level).toEqual("raid-1");
3046 expect(modes[2].level).toEqual("raid-5");3049 expect(modes[2].level).toEqual("raid-5");
3047 expect(modes[3].level).toEqual("raid-6");3050 expect(modes[3].level).toEqual("raid-6");
3051 expect(modes[4].level).toEqual("raid-10");
3052 expect(modes.length).toEqual(5);
3048 });3053 });
3049 });3054 });
30503055
@@ -3070,6 +3075,11 @@
3070 level: "raid-6",3075 level: "raid-6",
3071 min_disks: 4,3076 min_disks: 4,
3072 allows_spares: true3077 allows_spares: true
3078 },
3079 {
3080 level: "raid-10",
3081 min_disks: 3,
3082 allows_spares: true
3073 }3083 }
3074 ];3084 ];
30753085
@@ -3323,6 +3333,7 @@
3323 $scope.availableNew.mode = $scope.getAvailableRAIDModes()[2];3333 $scope.availableNew.mode = $scope.getAvailableRAIDModes()[2];
3324 $scope.setAsSpareRAIDMember(spare0);3334 $scope.setAsSpareRAIDMember(spare0);
33253335
3336 // The 1MB spare causes us to only use 1MB of each active disk.
3326 expect($scope.getNewRAIDSize()).toBe("2.0 MB");3337 expect($scope.getNewRAIDSize()).toBe("2.0 MB");
3327 });3338 });
33283339
@@ -3358,8 +3369,40 @@
3358 $scope.availableNew.mode = $scope.getAvailableRAIDModes()[3];3369 $scope.availableNew.mode = $scope.getAvailableRAIDModes()[3];
3359 $scope.setAsSpareRAIDMember(spare0);3370 $scope.setAsSpareRAIDMember(spare0);
33603371
3372 // The 1MB spare causes us to only use 1MB of each active disk.
3361 expect($scope.getNewRAIDSize()).toBe("2.0 MB");3373 expect($scope.getNewRAIDSize()).toBe("2.0 MB");
3362 });3374 });
3375
3376 it("gets proper raid-10 size", function() {
3377 var controller = makeController();
3378 var disk0 = {
3379 original: {
3380 available_size: 2 * 1000 * 1000
3381 }
3382 };
3383 var disk1 = {
3384 original: {
3385 available_size: 2 * 1000 * 1000
3386 }
3387 };
3388 var disk2 = {
3389 original: {
3390 available_size: 2 * 1000 * 1000
3391 }
3392 };
3393 var spare0 = {
3394 original: {
3395 available_size: 1000 * 1000
3396 }
3397 };
3398 $scope.availableNew.spares = [];
3399 $scope.availableNew.devices = [disk0, disk1, disk2, spare0];
3400 $scope.availableNew.mode = $scope.getAvailableRAIDModes()[4];
3401 $scope.setAsSpareRAIDMember(spare0);
3402
3403 // The 1MB spare causes us to only use 1MB of each active disk.
3404 expect($scope.getNewRAIDSize()).toBe("1.5 MB");
3405 });
3363 });3406 });
33643407
3365 describe("createRAIDCanSave", function() {3408 describe("createRAIDCanSave", function() {
33663409
=== modified file 'src/maasserver/testing/factory.py'
--- src/maasserver/testing/factory.py 2015-10-28 22:03:20 +0000
+++ src/maasserver/testing/factory.py 2015-10-29 13:27:52 +0000
@@ -1395,6 +1395,18 @@
1395 fstype=FILESYSTEM_TYPE.RAID_SPARE,1395 fstype=FILESYSTEM_TYPE.RAID_SPARE,
1396 block_device=spare_block_device)1396 block_device=spare_block_device)
1397 group.filesystems.add(spare_filesystem)1397 group.filesystems.add(spare_filesystem)
1398 elif group_type == FILESYSTEM_GROUP_TYPE.RAID_10:
1399 for _ in range(4):
1400 block_device = self.make_PhysicalBlockDevice(node)
1401 filesystem = self.make_Filesystem(
1402 fstype=FILESYSTEM_TYPE.RAID,
1403 block_device=block_device)
1404 group.filesystems.add(filesystem)
1405 spare_block_device = self.make_PhysicalBlockDevice(node)
1406 spare_filesystem = self.make_Filesystem(
1407 fstype=FILESYSTEM_TYPE.RAID_SPARE,
1408 block_device=spare_block_device)
1409 group.filesystems.add(spare_filesystem)
1398 elif group_type == FILESYSTEM_GROUP_TYPE.BCACHE:1410 elif group_type == FILESYSTEM_GROUP_TYPE.BCACHE:
1399 backing_block_device = self.make_PhysicalBlockDevice(node)1411 backing_block_device = self.make_PhysicalBlockDevice(node)
1400 backing_filesystem = self.make_Filesystem(1412 backing_filesystem = self.make_Filesystem(
14011413
=== modified file 'src/maasserver/tests/test_forms_raid.py'
--- src/maasserver/tests/test_forms_raid.py 2015-10-28 01:59:30 +0000
+++ src/maasserver/tests/test_forms_raid.py 2015-10-29 13:27:52 +0000
@@ -261,6 +261,7 @@
261 FILESYSTEM_GROUP_TYPE.RAID_1,261 FILESYSTEM_GROUP_TYPE.RAID_1,
262 FILESYSTEM_GROUP_TYPE.RAID_5,262 FILESYSTEM_GROUP_TYPE.RAID_5,
263 FILESYSTEM_GROUP_TYPE.RAID_6,263 FILESYSTEM_GROUP_TYPE.RAID_6,
264 FILESYSTEM_GROUP_TYPE.RAID_10,
264 ]:265 ]:
265 form = CreateRaidForm(node=node, data={266 form = CreateRaidForm(node=node, data={
266 'name': 'md1',267 'name': 'md1',