diff --git a/lib/objects.py b/lib/objects.py index fc077b38e213bc4639eb5354d08216fd65cb9a9b..0a15e98dae55525cbdf7493307ce279ee9e2f18f 100644 --- a/lib/objects.py +++ b/lib/objects.py @@ -989,6 +989,40 @@ class OS(ConfigObject): return cls.SplitNameVariant(name)[1] +class NodeHvState(ConfigObject): + """Hypvervisor state on a node. + + @ivar mem_total: Total amount of memory + @ivar mem_node: Memory used by, or reserved for, the node itself (not always + available) + @ivar mem_hv: Memory used by hypervisor or lost due to instance allocation + rounding + @ivar mem_inst: Memory used by instances living on node + @ivar cpu_total: Total node CPU core count + @ivar cpu_node: Number of CPU cores reserved for the node itself + + """ + __slots__ = [ + "mem_total", + "mem_node", + "mem_hv", + "mem_inst", + "cpu_total", + "cpu_node", + ] + _TIMESTAMPS + + +class NodeDiskState(ConfigObject): + """Disk state on a node. + + """ + __slots__ = [ + "total", + "reserved", + "overhead", + ] + _TIMESTAMPS + + class Node(TaggableObject): """Config object representing a node. @@ -1035,6 +1069,41 @@ class Node(TaggableObject): if self.powered is None: self.powered = True + def ToDict(self): + """Custom function for serializing. + + """ + data = super(Node, self).ToDict() + + hv_state = data.get("hv_state", None) + if hv_state is not None: + data["hv_state"] = self._ContainerToDicts(hv_state) + + disk_state = data.get("disk_state", None) + if disk_state is not None: + data["disk_state"] = \ + dict((key, self._ContainerToDicts(value)) + for (key, value) in disk_state.items()) + + return data + + @classmethod + def FromDict(cls, val): + """Custom function for deserializing. + + """ + obj = super(Node, cls).FromDict(val) + + if obj.hv_state is not None: + obj.hv_state = cls._ContainerFromDicts(obj.hv_state, dict, NodeHvState) + + if obj.disk_state is not None: + obj.disk_state = \ + dict((key, cls._ContainerFromDicts(value, dict, NodeDiskState)) + for (key, value) in obj.disk_state.items()) + + return obj + class NodeGroup(TaggableObject): """Config object representing a node group.""" diff --git a/test/ganeti.objects_unittest.py b/test/ganeti.objects_unittest.py index 23f2e28b0ca57f20c75829913e5174b623f616cb..20b63f1ba5f04bd3b163a29150d702c1151ad79e 100755 --- a/test/ganeti.objects_unittest.py +++ b/test/ganeti.objects_unittest.py @@ -283,5 +283,54 @@ class TestInstance(unittest.TestCase): self.assertRaises(errors.OpPrereqError, inst.FindDisk, 1) +class TestNode(unittest.TestCase): + def testEmpty(self): + self.assertEqual(objects.Node().ToDict(), {}) + self.assertTrue(isinstance(objects.Node.FromDict({}), objects.Node)) + + def testHvState(self): + node = objects.Node(name="node18157.example.com", hv_state={ + constants.HT_XEN_HVM: objects.NodeHvState(cpu_total=64), + constants.HT_KVM: objects.NodeHvState(cpu_node=1), + }) + + node2 = objects.Node.FromDict(node.ToDict()) + + # Make sure nothing can reference it anymore + del node + + self.assertEqual(node2.name, "node18157.example.com") + self.assertEqual(frozenset(node2.hv_state), frozenset([ + constants.HT_XEN_HVM, + constants.HT_KVM, + ])) + self.assertEqual(node2.hv_state[constants.HT_KVM].cpu_node, 1) + self.assertEqual(node2.hv_state[constants.HT_XEN_HVM].cpu_total, 64) + + def testDiskState(self): + node = objects.Node(name="node32087.example.com", disk_state={ + constants.LD_LV: { + "lv32352": objects.NodeDiskState(total=128), + "lv2082": objects.NodeDiskState(total=512), + }, + }) + + node2 = objects.Node.FromDict(node.ToDict()) + + # Make sure nothing can reference it anymore + del node + + self.assertEqual(node2.name, "node32087.example.com") + self.assertEqual(frozenset(node2.disk_state), frozenset([ + constants.LD_LV, + ])) + self.assertEqual(frozenset(node2.disk_state[constants.LD_LV]), frozenset([ + "lv32352", + "lv2082", + ])) + self.assertEqual(node2.disk_state[constants.LD_LV]["lv2082"].total, 512) + self.assertEqual(node2.disk_state[constants.LD_LV]["lv32352"].total, 128) + + if __name__ == '__main__': testutils.GanetiTestProgram()