Merge ~ack/maas:1848043-websocket-storage-vol-numa into maas:master

Proposed by Alberto Donato
Status: Merged
Approved by: Alberto Donato
Approved revision: e216dc92901f7a0cb768ba0c96c0a99e9d20a041
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ack/maas:1848043-websocket-storage-vol-numa
Merge into: maas:master
Diff against target: 449 lines (+277/-6)
9 files modified
src/maasserver/models/cacheset.py (+23/-0)
src/maasserver/models/filesystem.py (+16/-0)
src/maasserver/models/filesystemgroup.py (+17/-0)
src/maasserver/models/tests/test_cacheset.py (+34/-0)
src/maasserver/models/tests/test_filesystem.py (+41/-1)
src/maasserver/models/tests/test_filesystemgroup.py (+85/-0)
src/maasserver/models/virtualblockdevice.py (+4/-5)
src/maasserver/websockets/handlers/node.py (+2/-0)
src/maasserver/websockets/handlers/tests/test_machine.py (+55/-0)
Reviewer Review Type Date Requested Status
Newell Jensen (community) Approve
MAAS Lander Approve
Review via email: mp+374429@code.launchpad.net

Commit message

LP: #1848043 - Add numa node indexes to websocket dehydration of CacheSets and FilesystemGroups

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b 1848043-websocket-storage-vol-numa lp:~ack/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci-jenkins.internal:8080/job/maas/job/branch-tester/6832/console
COMMIT: 81d12ff2826704bfd2bd18c9ea26c132b9e7858c

review: Needs Fixing
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b 1848043-websocket-storage-vol-numa lp:~ack/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci-jenkins.internal:8080/job/maas/job/branch-tester/6835/console
COMMIT: 4a507375d22fcb9789dc7b7aaa12f2463d36a929

review: Needs Fixing
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b 1848043-websocket-storage-vol-numa lp:~ack/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: e216dc92901f7a0cb768ba0c96c0a99e9d20a041

review: Approve
Revision history for this message
Newell Jensen (newell-jensen) wrote :

LGTM

review: Approve

There was an error fetching revisions from git servers. Please try again in a few minutes. If the problem persists, contact Launchpad support.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/maasserver/models/cacheset.py b/src/maasserver/models/cacheset.py
index 97996e2..5246454 100644
--- a/src/maasserver/models/cacheset.py
+++ b/src/maasserver/models/cacheset.py
@@ -5,6 +5,7 @@
55
6__all__ = ["CacheSet"]6__all__ = ["CacheSet"]
77
8from itertools import chain
89
9from django.core.exceptions import PermissionDenied10from django.core.exceptions import PermissionDenied
10from django.db.models import Manager, Q11from django.db.models import Manager, Q
@@ -13,6 +14,7 @@ from django.http import Http404
13from maasserver import DefaultMeta14from maasserver import DefaultMeta
14from maasserver.enum import FILESYSTEM_TYPE15from maasserver.enum import FILESYSTEM_TYPE
15from maasserver.models.cleansave import CleanSave16from maasserver.models.cleansave import CleanSave
17from maasserver.models.numa import NUMANode
16from maasserver.models.timestampedmodel import TimestampedModel18from maasserver.models.timestampedmodel import TimestampedModel
1719
1820
@@ -188,3 +190,24 @@ class CacheSet(CleanSave, TimestampedModel):
188 return None190 return None
189 else:191 else:
190 return filesystem.get_parent()192 return filesystem.get_parent()
193
194 def get_numa_node_indexes(self):
195 """Return NUMA node indexes for physical devices making up the cacheset."""
196 numa_node_indexes = set(
197 chain(
198 *(
199 fsgroup.get_numa_node_indexes()
200 for fsgroup in self.filesystemgroup_set.all()
201 )
202 )
203 )
204 filesystem = self.get_filesystem()
205 if filesystem:
206 block_devices = filesystem.get_physical_block_devices()
207 numa_ids = set(device.numa_node_id for device in block_devices)
208 numa_node_indexes.update(
209 NUMANode.objects.filter(id__in=numa_ids)
210 .values_list("index", flat=True)
211 .order_by("index")
212 )
213 return sorted(numa_node_indexes)
diff --git a/src/maasserver/models/filesystem.py b/src/maasserver/models/filesystem.py
index cc591c9..a34f4d7 100644
--- a/src/maasserver/models/filesystem.py
+++ b/src/maasserver/models/filesystem.py
@@ -29,6 +29,7 @@ from maasserver.models.cacheset import CacheSet
29from maasserver.models.cleansave import CleanSave29from maasserver.models.cleansave import CleanSave
30from maasserver.models.filesystemgroup import FilesystemGroup30from maasserver.models.filesystemgroup import FilesystemGroup
31from maasserver.models.partition import Partition31from maasserver.models.partition import Partition
32from maasserver.models.physicalblockdevice import PhysicalBlockDevice
32from maasserver.models.timestampedmodel import TimestampedModel33from maasserver.models.timestampedmodel import TimestampedModel
3334
3435
@@ -170,6 +171,21 @@ class Filesystem(CleanSave, TimestampedModel):
170 # XXX: Explode instead?171 # XXX: Explode instead?
171 return None172 return None
172173
174 def get_physical_block_devices(self):
175 """Return PhysicalBlockDevices backing the filesystem."""
176 from maasserver.models.virtualblockdevice import VirtualBlockDevice
177
178 devices = []
179 parent = self.get_parent()
180 if isinstance(parent, PhysicalBlockDevice):
181 devices.append(parent)
182 elif isinstance(parent, VirtualBlockDevice):
183 for grandparent in parent.get_parents():
184 device = grandparent.actual_instance
185 if isinstance(device, PhysicalBlockDevice):
186 devices.append(device)
187 return devices
188
173 def get_size(self):189 def get_size(self):
174 """Size of filesystem."""190 """Size of filesystem."""
175 if self.partition is not None:191 if self.partition is not None:
diff --git a/src/maasserver/models/filesystemgroup.py b/src/maasserver/models/filesystemgroup.py
index 319e3a0..c3b9bb3 100644
--- a/src/maasserver/models/filesystemgroup.py
+++ b/src/maasserver/models/filesystemgroup.py
@@ -6,6 +6,7 @@ a virtual block device. E.g. LVM Volume Group."""
66
7__all__ = ["Bcache", "FilesystemGroup", "RAID", "VMFS", "VolumeGroup"]7__all__ = ["Bcache", "FilesystemGroup", "RAID", "VMFS", "VolumeGroup"]
88
9from itertools import chain
9from uuid import uuid410from uuid import uuid4
1011
11from django.core.exceptions import PermissionDenied, ValidationError12from django.core.exceptions import PermissionDenied, ValidationError
@@ -24,6 +25,7 @@ from maasserver.enum import (
24)25)
25from maasserver.models.cacheset import CacheSet26from maasserver.models.cacheset import CacheSet
26from maasserver.models.cleansave import CleanSave27from maasserver.models.cleansave import CleanSave
28from maasserver.models.numa import NUMANode
27from maasserver.models.timestampedmodel import TimestampedModel29from maasserver.models.timestampedmodel import TimestampedModel
28from maasserver.utils.orm import get_one30from maasserver.utils.orm import get_one
2931
@@ -392,6 +394,21 @@ class FilesystemGroup(CleanSave, TimestampedModel):
392 # that cache will be used.394 # that cache will be used.
393 return get_one(self.virtual_devices.all())395 return get_one(self.virtual_devices.all())
394396
397 def get_numa_node_indexes(self):
398 """Return NUMA node indexes for physical devices making the volume group."""
399 block_devices = chain(
400 *(
401 filesystem.get_physical_block_devices()
402 for filesystem in self.filesystems.all()
403 )
404 )
405 numa_ids = set(device.numa_node_id for device in block_devices)
406 return list(
407 NUMANode.objects.filter(id__in=numa_ids)
408 .values_list("index", flat=True)
409 .order_by("index")
410 )
411
395 def get_node(self):412 def get_node(self):
396 """`Node` this filesystem group belongs to."""413 """`Node` this filesystem group belongs to."""
397 if self.filesystems.count() == 0:414 if self.filesystems.count() == 0:
diff --git a/src/maasserver/models/tests/test_cacheset.py b/src/maasserver/models/tests/test_cacheset.py
index 6009a11..6341ea5 100644
--- a/src/maasserver/models/tests/test_cacheset.py
+++ b/src/maasserver/models/tests/test_cacheset.py
@@ -10,6 +10,7 @@ import random
10from django.core.exceptions import PermissionDenied10from django.core.exceptions import PermissionDenied
11from django.http import Http40411from django.http import Http404
1212
13from maasserver.enum import FILESYSTEM_GROUP_TYPE, FILESYSTEM_TYPE
13from maasserver.models import CacheSet14from maasserver.models import CacheSet
14from maasserver.permissions import NodePermission15from maasserver.permissions import NodePermission
15from maasserver.testing.factory import factory16from maasserver.testing.factory import factory
@@ -283,3 +284,36 @@ class TestCacheSet(MAASServerTestCase):
283 block_device = factory.make_PhysicalBlockDevice()284 block_device = factory.make_PhysicalBlockDevice()
284 cache_set = factory.make_CacheSet(block_device=block_device)285 cache_set = factory.make_CacheSet(block_device=block_device)
285 self.assertEqual(block_device, cache_set.get_device())286 self.assertEqual(block_device, cache_set.get_device())
287
288 def test_get_numa_nodes_indexes_only_own_device(self):
289 block_device = factory.make_PhysicalBlockDevice()
290 cache_set = factory.make_CacheSet(block_device=block_device)
291 self.assertEqual(cache_set.get_numa_node_indexes(), [0])
292
293 def test_get_numa_nodes_indexes_many_devices(self):
294 node = factory.make_Node()
295 numa_nodes = [
296 node.default_numanode,
297 factory.make_NUMANode(node=node),
298 factory.make_NUMANode(node=node),
299 ]
300 block_devices = [
301 factory.make_PhysicalBlockDevice(numa_node=numa_node)
302 for numa_node in numa_nodes
303 ]
304 filesystems = [
305 factory.make_Filesystem(
306 fstype=FILESYSTEM_TYPE.LVM_PV, block_device=block_device
307 )
308 for block_device in block_devices
309 ]
310 fsgroup = factory.make_FilesystemGroup(
311 node=node,
312 filesystems=filesystems,
313 group_type=FILESYSTEM_GROUP_TYPE.LVM_VG,
314 )
315 virtual_block_device = factory.make_VirtualBlockDevice(
316 filesystem_group=fsgroup
317 )
318 cache_set = factory.make_CacheSet(block_device=virtual_block_device)
319 self.assertEqual(cache_set.get_numa_node_indexes(), [0, 1, 2])
diff --git a/src/maasserver/models/tests/test_filesystem.py b/src/maasserver/models/tests/test_filesystem.py
index e97865b..b2da0b5 100644
--- a/src/maasserver/models/tests/test_filesystem.py
+++ b/src/maasserver/models/tests/test_filesystem.py
@@ -15,7 +15,11 @@ from testscenarios import multiply_scenarios
15from testtools import ExpectedException15from testtools import ExpectedException
16from testtools.matchers import Equals, Is, IsInstance, MatchesStructure16from testtools.matchers import Equals, Is, IsInstance, MatchesStructure
1717
18from maasserver.enum import FILESYSTEM_FORMAT_TYPE_CHOICES_DICT18from maasserver.enum import (
19 FILESYSTEM_FORMAT_TYPE_CHOICES_DICT,
20 FILESYSTEM_GROUP_TYPE,
21 FILESYSTEM_TYPE,
22)
19from maasserver.models.filesystem import Filesystem23from maasserver.models.filesystem import Filesystem
20from maasserver.testing.factory import factory24from maasserver.testing.factory import factory
21from maasserver.testing.testcase import MAASServerTestCase25from maasserver.testing.testcase import MAASServerTestCase
@@ -71,6 +75,42 @@ class TestFilesystem(MAASServerTestCase):
71 fs = Filesystem()75 fs = Filesystem()
72 self.assertIsNone(fs.get_node())76 self.assertIsNone(fs.get_node())
7377
78 def test_get_physical_block_devices_single(self):
79 node = factory.make_Node()
80 block_device = factory.make_PhysicalBlockDevice(node=node)
81 filesystem = factory.make_Filesystem(
82 fstype=FILESYSTEM_TYPE.LVM_PV, block_device=block_device
83 )
84 self.assertEqual(
85 filesystem.get_physical_block_devices(), [block_device]
86 )
87
88 def test_get_physical_block_devices_multiple(self):
89 node = factory.make_Node()
90 block_devices = [
91 factory.make_PhysicalBlockDevice(node=node) for _ in range(3)
92 ]
93 filesystems = [
94 factory.make_Filesystem(
95 fstype=FILESYSTEM_TYPE.LVM_PV, block_device=block_device
96 )
97 for block_device in block_devices
98 ]
99 fsgroup = factory.make_FilesystemGroup(
100 node=node,
101 filesystems=filesystems,
102 group_type=FILESYSTEM_GROUP_TYPE.LVM_VG,
103 )
104 virtual_block_device = factory.make_VirtualBlockDevice(
105 filesystem_group=fsgroup
106 )
107 filesystem = factory.make_Filesystem(
108 fstype=FILESYSTEM_TYPE.LVM_PV, block_device=virtual_block_device
109 )
110 self.assertEqual(
111 filesystem.get_physical_block_devices(), block_devices
112 )
113
74 def test_get_size_returns_partition_size(self):114 def test_get_size_returns_partition_size(self):
75 partition = factory.make_Partition()115 partition = factory.make_Partition()
76 fs = factory.make_Filesystem(partition=partition)116 fs = factory.make_Filesystem(partition=partition)
diff --git a/src/maasserver/models/tests/test_filesystemgroup.py b/src/maasserver/models/tests/test_filesystemgroup.py
index 4fe263a..a84f46b 100644
--- a/src/maasserver/models/tests/test_filesystemgroup.py
+++ b/src/maasserver/models/tests/test_filesystemgroup.py
@@ -684,6 +684,91 @@ class TestFilesystemGroup(MAASServerTestCase):
684 fsgroup.virtual_device,684 fsgroup.virtual_device,
685 )685 )
686686
687 def test_get_numa_node_indexes_all_same(self):
688 fsgroup = factory.make_FilesystemGroup(
689 group_type=factory.pick_enum(
690 FILESYSTEM_GROUP_TYPE, but_not=FILESYSTEM_GROUP_TYPE.VMFS6
691 )
692 )
693 self.assertEqual(fsgroup.get_numa_node_indexes(), [0])
694
695 def test_get_numa_node_indexes_multiple(self):
696 node = factory.make_Node()
697 numa_nodes = [
698 node.default_numanode,
699 factory.make_NUMANode(node=node),
700 factory.make_NUMANode(node=node),
701 ]
702 block_devices = [
703 factory.make_PhysicalBlockDevice(numa_node=numa_node)
704 for numa_node in numa_nodes
705 ]
706 filesystems = [
707 factory.make_Filesystem(
708 fstype=FILESYSTEM_TYPE.LVM_PV, block_device=block_device
709 )
710 for block_device in block_devices
711 ]
712 fsgroup = factory.make_FilesystemGroup(
713 node=node,
714 filesystems=filesystems,
715 group_type=FILESYSTEM_GROUP_TYPE.LVM_VG,
716 )
717 self.assertEqual(fsgroup.get_numa_node_indexes(), [0, 1, 2])
718
719 def test_get_numa_node_indexes_nested(self):
720 node = factory.make_Node()
721 numa_nodes = [
722 node.default_numanode,
723 factory.make_NUMANode(node=node),
724 factory.make_NUMANode(node=node),
725 factory.make_NUMANode(node=node),
726 factory.make_NUMANode(node=node),
727 ]
728 # 2 physical disks have filesystems on them directly
729 filesystems = [
730 factory.make_Filesystem(
731 fstype=FILESYSTEM_TYPE.LVM_PV,
732 block_device=factory.make_PhysicalBlockDevice(
733 numa_node=numa_node
734 ),
735 )
736 for numa_node in numa_nodes[:2]
737 ]
738
739 # the 3 remaining disks are part of another filesystem group which gets
740 # added to the first
741 nested_filesystems = [
742 factory.make_Filesystem(
743 fstype=FILESYSTEM_TYPE.LVM_PV,
744 block_device=factory.make_PhysicalBlockDevice(
745 numa_node=numa_node
746 ),
747 )
748 for numa_node in numa_nodes[2:]
749 ]
750 nested_group = factory.make_FilesystemGroup(
751 node=node,
752 filesystems=nested_filesystems,
753 group_type=FILESYSTEM_GROUP_TYPE.LVM_VG,
754 )
755 virtual_block_device = factory.make_VirtualBlockDevice(
756 filesystem_group=nested_group
757 )
758 filesystems.append(
759 factory.make_Filesystem(
760 fstype=FILESYSTEM_TYPE.LVM_PV,
761 block_device=virtual_block_device,
762 )
763 )
764
765 fsgroup = factory.make_FilesystemGroup(
766 node=node,
767 filesystems=filesystems,
768 group_type=FILESYSTEM_GROUP_TYPE.LVM_VG,
769 )
770 self.assertEqual(fsgroup.get_numa_node_indexes(), [0, 1, 2, 3, 4])
771
687 def test_get_node_returns_first_filesystem_node(self):772 def test_get_node_returns_first_filesystem_node(self):
688 fsgroup = factory.make_FilesystemGroup()773 fsgroup = factory.make_FilesystemGroup()
689 self.assertEqual(774 self.assertEqual(
diff --git a/src/maasserver/models/virtualblockdevice.py b/src/maasserver/models/virtualblockdevice.py
index 9b9bb65..b59be68 100644
--- a/src/maasserver/models/virtualblockdevice.py
+++ b/src/maasserver/models/virtualblockdevice.py
@@ -153,13 +153,12 @@ class VirtualBlockDevice(BlockDevice):
153 return False153 return False
154 else:154 else:
155 return False155 return False
156 for virtual_device in fs_group.virtual_devices.all():156
157 if virtual_device.id == self.id:157 # whether the device is part of the filesystem group
158 return True158 return fs_group.virtual_devices.filter(id=self.id).exists()
159 return False
160159
161 parents = []160 parents = []
162 # We need to check all of the nodes block devices incase161 # We need to check all of the nodes block devices in case
163 # we have nested virtual block devices.162 # we have nested virtual block devices.
164 for block_device in self.node.blockdevice_set.all():163 for block_device in self.node.blockdevice_set.all():
165 if block_device.id == self.id:164 if block_device.id == self.id:
diff --git a/src/maasserver/websockets/handlers/node.py b/src/maasserver/websockets/handlers/node.py
index 7b47bca..e214716 100644
--- a/src/maasserver/websockets/handlers/node.py
+++ b/src/maasserver/websockets/handlers/node.py
@@ -553,6 +553,7 @@ class NodeHandler(TimestampedModelHandler):
553 "used_for": "volume group",553 "used_for": "volume group",
554 "filesystem": None,554 "filesystem": None,
555 "partitions": None,555 "partitions": None,
556 "numa_nodes": volume_group.get_numa_node_indexes(),
556 }557 }
557558
558 def dehydrate_cache_set(self, cache_set):559 def dehydrate_cache_set(self, cache_set):
@@ -582,6 +583,7 @@ class NodeHandler(TimestampedModelHandler):
582 "used_for": ", ".join(bcache_devices),583 "used_for": ", ".join(bcache_devices),
583 "filesystem": None,584 "filesystem": None,
584 "partitions": None,585 "partitions": None,
586 "numa_nodes": cache_set.get_numa_node_indexes(),
585 }587 }
586588
587 def dehydrate_partitions(self, partition_table):589 def dehydrate_partitions(self, partition_table):
diff --git a/src/maasserver/websockets/handlers/tests/test_machine.py b/src/maasserver/websockets/handlers/tests/test_machine.py
index 7144d1e..010e8bc 100644
--- a/src/maasserver/websockets/handlers/tests/test_machine.py
+++ b/src/maasserver/websockets/handlers/tests/test_machine.py
@@ -989,10 +989,40 @@ class TestMachineHandler(MAASServerTestCase):
989 "used_for": "volume group",989 "used_for": "volume group",
990 "filesystem": None,990 "filesystem": None,
991 "partitions": None,991 "partitions": None,
992 "numa_nodes": [0],
992 },993 },
993 handler.dehydrate_volume_group(volume_group),994 handler.dehydrate_volume_group(volume_group),
994 )995 )
995996
997 def test_dehydrate_volume_group_multiple_numa_nodes(self):
998 owner = factory.make_User()
999 node = factory.make_Node(owner=owner)
1000 numa_nodes = [
1001 node.default_numanode,
1002 factory.make_NUMANode(node=node),
1003 factory.make_NUMANode(node=node),
1004 ]
1005 block_devices = [
1006 factory.make_PhysicalBlockDevice(numa_node=numa_node)
1007 for numa_node in numa_nodes
1008 ]
1009 filesystems = [
1010 factory.make_Filesystem(
1011 fstype=FILESYSTEM_TYPE.LVM_PV, block_device=block_device
1012 )
1013 for block_device in block_devices
1014 ]
1015 volume_group = factory.make_FilesystemGroup(
1016 node=node,
1017 filesystems=filesystems,
1018 group_type=FILESYSTEM_GROUP_TYPE.LVM_VG,
1019 )
1020 handler = MachineHandler(owner, {}, None)
1021 self.assertEqual(
1022 handler.dehydrate_volume_group(volume_group)["numa_nodes"],
1023 [0, 1, 2],
1024 )
1025
996 def test_dehydrate_cache_set(self):1026 def test_dehydrate_cache_set(self):
997 owner = factory.make_User()1027 owner = factory.make_User()
998 node = factory.make_Node(owner=owner)1028 node = factory.make_Node(owner=owner)
@@ -1041,10 +1071,35 @@ class TestMachineHandler(MAASServerTestCase):
1041 ),1071 ),
1042 "filesystem": None,1072 "filesystem": None,
1043 "partitions": None,1073 "partitions": None,
1074 "numa_nodes": [0],
1044 },1075 },
1045 handler.dehydrate_cache_set(cache_set),1076 handler.dehydrate_cache_set(cache_set),
1046 )1077 )
10471078
1079 def test_dehydrate_cache_set_multiple_numa_nodes(self):
1080 owner = factory.make_User()
1081 node = factory.make_Node(owner=owner)
1082 numa_nodes = [
1083 node.default_numanode,
1084 factory.make_NUMANode(node=node),
1085 factory.make_NUMANode(node=node),
1086 ]
1087 cache_set = factory.make_CacheSet(node=node)
1088 for numa_node in numa_nodes:
1089 backing = factory.make_PhysicalBlockDevice(numa_node=numa_node)
1090 fs = factory.make_Filesystem(
1091 block_device=backing, fstype=FILESYSTEM_TYPE.BCACHE_BACKING
1092 )
1093 factory.make_FilesystemGroup(
1094 group_type=FILESYSTEM_GROUP_TYPE.BCACHE,
1095 filesystems=[fs],
1096 cache_set=cache_set,
1097 )
1098 handler = MachineHandler(owner, {}, None)
1099 self.assertEqual(
1100 handler.dehydrate_cache_set(cache_set)["numa_nodes"], [0, 1, 2]
1101 )
1102
1048 def test_dehydrate_partitions_returns_None(self):1103 def test_dehydrate_partitions_returns_None(self):
1049 owner = factory.make_User()1104 owner = factory.make_User()
1050 handler = MachineHandler(owner, {}, None)1105 handler = MachineHandler(owner, {}, None)

Subscribers

People subscribed via source and target branches