← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~gz/maas/populate_mem_and_cpu into lp:maas

 

Martin Packman has proposed merging lp:~gz/maas/populate_mem_and_cpu into lp:maas with lp:~gz/maas/store_lshw_in_node as a prerequisite.

Requested reviews:
  MAAS Maintainers (maas-maintainers)

For more details, see:
https://code.launchpad.net/~gz/maas/populate_mem_and_cpu/+merge/125705

Updates cpu_count and memory fields on node when hardware_details gets set. This is much uglier than anticipated for a variety of reasons, mostly django related.

I tried and failed to get around django to just update the fields, so this does a bunch of extra steps. There may well be a better way, but unfortunatly just accessing sql functions does require raw sql.

Because proper reporting on objects other than node-sets from xpath wasn't implemented till postgres 9.2, I needed the following changes to the queries to do some operations in sql rather than in the query:

    (xpath(%s, hardware_details))[1], 
        "count(//node[@id='core']/node[@class='processor'])"
->
    array_length(xpath(%s, hardware_details), 1),
        "//node[@id='core']/node[@class='processor']"


    (xpath(%s, hardware_details))[1],
        "/node[@id='memory']/size[@units='bytes'] div 107374182"
->
    (xpath(%s, hardware_details))[1]::text::bigint / 1073741824",
        "/node[@id='memory']/size[@units='bytes']/text()"

Fortunately this won't affect tags, which should just be able to use the simpler xpath_exists function.
-- 
https://code.launchpad.net/~gz/maas/populate_mem_and_cpu/+merge/125705
Your team MAAS Maintainers is requested to review the proposed merge of lp:~gz/maas/populate_mem_and_cpu into lp:maas.
=== modified file 'src/maasserver/models/node.py'
--- src/maasserver/models/node.py	2012-09-21 13:12:23 +0000
+++ src/maasserver/models/node.py	2012-09-21 13:12:23 +0000
@@ -13,6 +13,7 @@
 __all__ = [
     "NODE_TRANSITIONS",
     "Node",
+    "update_hardware_details",
     ]
 
 import os
@@ -25,6 +26,9 @@
     PermissionDenied,
     ValidationError,
     )
+from django.db import (
+    connection,
+    )
 from django.db.models import (
     BooleanField,
     CharField,
@@ -318,6 +322,35 @@
         return processed_nodes
 
 
+
+def update_hardware_details(node, xmlbytes):
+    """Set node hardware_details from lshw output and update related fields
+
+    There are a bunch of suboptimal things here:
+    * Is a function rather than method in hope south migration can reuse.
+    * Doing UPDATE then transaction.commit_unless_managed doesn't work?
+    * Scalar returns from xpath() work in postgres 9.2 or later only.
+    """
+    node.hardware_details = xmlbytes
+    node.save()
+    cursor = connection.cursor()
+    cursor.execute("SELECT"
+        " array_length(xpath(%s, hardware_details), 1) AS count"
+        ", (xpath(%s, hardware_details))[1]::text::bigint / 1073741824 AS mem"
+        " FROM maasserver_node"
+        " WHERE id = %s",
+        [
+            "//node[@id='core']/node[@class='processor']",
+            "//node[@id='memory']/size[@units='bytes']/text()",
+            node.id,
+        ])
+    cpu_count, memory = cursor.fetchone()
+    node.cpu_count = cpu_count or 0
+    node.memory = memory or 0
+    node.save()
+    # TODO: update node-tag links
+
+
 class Node(CleanSave, TimestampedModel):
     """A `Node` represents a physical machine used by the MAAS Server.
 
@@ -635,5 +668,4 @@
 
     def set_hardware_details(self, xmlbytes):
         """Set the `lshw -xml` output"""
-        self.hardware_details = xmlbytes
-        self.save()
+        update_hardware_details(self, xmlbytes)

=== modified file 'src/metadataserver/tests/test_api.py'
--- src/metadataserver/tests/test_api.py	2012-09-21 13:12:23 +0000
+++ src/metadataserver/tests/test_api.py	2012-09-21 13:12:23 +0000
@@ -503,6 +503,31 @@
         node = reload_object(node)
         self.assertEqual(xmlbytes, node.hardware_details)
 
+    def test_signal_stores_lshw_with_cpu_count(self):
+        node = factory.make_node(status=NODE_STATUS.COMMISSIONING)
+        client = self.make_node_client(node=node)
+        xmlbytes = (
+            '<node id="core">'
+                '<node id="cpu:0" class="processor"/>'
+                '<node id="cpu:1" class="processor"/>'
+            '</node>').encode("utf-8")
+        response = self.call_signal(client, files={'01-lshw.out': xmlbytes})
+        self.assertEqual(httplib.OK, response.status_code)
+        node = reload_object(node)
+        self.assertEqual(2, node.cpu_count)
+
+    def test_signal_stores_lshw_with_memory(self):
+        node = factory.make_node(status=NODE_STATUS.COMMISSIONING)
+        client = self.make_node_client(node=node)
+        xmlbytes = (
+            '<node id="memory">'
+                '<size units="bytes">4294967296</size>'
+            '</node>').encode("utf-8")
+        response = self.call_signal(client, files={'01-lshw.out': xmlbytes})
+        self.assertEqual(httplib.OK, response.status_code)
+        node = reload_object(node)
+        self.assertEqual(4, node.memory)
+
     def test_api_retrieves_node_metadata_by_mac(self):
         mac = factory.make_mac_address()
         url = reverse(