Merge lp:~brendan-donegan/checkbox/bug960087_memory_compare_ram_devices into lp:checkbox

Proposed by Brendan Donegan
Status: Merged
Merged at revision: 1482
Proposed branch: lp:~brendan-donegan/checkbox/bug960087_memory_compare_ram_devices
Merge into: lp:checkbox
Diff against target: 211 lines (+103/-32) (has conflicts)
5 files modified
checkbox/lib/dmi.py (+16/-0)
checkbox/parsers/dmidecode.py (+4/-1)
debian/changelog (+9/-0)
scripts/dmi_resource (+4/-4)
scripts/memory_compare (+70/-27)
Text conflict in debian/changelog
To merge this branch: bzr merge lp:~brendan-donegan/checkbox/bug960087_memory_compare_ram_devices
Reviewer Review Type Date Requested Status
Marc Tardif (community) Approve
Brendan Donegan (community) Needs Resubmitting
Review via email: mp+112987@code.launchpad.net

Description of the change

I reimplemented and restructured the memory_compare script to use Python3 and also to store the dmi and meminfo output into dictionaries, which will allow for more flexibility later on if other fields need to be used to calculate the correct figures. This merge will also fix the bug where ROM devices for example are being included in the calculations, whereas we're only interested in RAM.

To post a comment you must log in.
1478. By Brendan Donegan

Merged from trunk

Revision history for this message
Marc Tardif (cr3) wrote :

Since the script is now written in Python, it should use the parsers in Checkbox to avoid duplicating that potentially error prone logic. Please modify the script to use checkbox.parsers.meminfo and checkbox.parsers.dmidecode. Thanks!

review: Needs Fixing
1479. By Brendan Donegan

Updated memory_compare to use meminfo parser from Checkbox instead of doing the parsing itself.

Revision history for this message
Brendan Donegan (brendan-donegan) wrote :

I've updated it to use the meminfo parser. As for the dmi parser, I agree with the fundamental principle of code re-use here, but I'm not too happy that every time I want to use a new attribute I have three files that need to be updated (the parser, the DmiDevice object and the script). I've also had to modify the dmi_resource script to prevent it crapping out because of the new attributes being used (which aren't universal so some checking had to be added). I'll update with the changes that need to be done to use the parser though and we can take it from there.

1480. By Brendan Donegan

Refactored memory_compare python version to use DmidecodeParser

Revision history for this message
Brendan Donegan (brendan-donegan) wrote :

I've made the necessary change to dmidecode.py and dmi.py to support the two extra attributes I need. I also extended dmi_resource.py to include them - let me know if you'd rather this wasn't included since it's a little outside the scope of this merge.

review: Needs Resubmitting
Revision history for this message
Marc Tardif (cr3) wrote :

In checkbox.lib.dmi, you added:

+ @property
+ def size(self):
+ attribute = "%s_size" % self.category.lower()
+ size = self._attributes.get(attribute)
+
+ size = int(size.split()[0]) * 1024
+
+ if size:
+ return size
+
+ return None

First, when the attribute exists, it will always interpret the size in kilobytes since it ignores the type in the split. Instead, you should use the string_to_type function defined in checkbox.lib.conversion.

Second, when the attribute doesn't exist, the split() method will fail horribly on a None value. So, I would suggest you write the size property method like this, remembering to import string_to_type at the beginning of the module of course:

+ @property
+ def size(self):
+ attribute = "%s_size" % self.category.lower()
+ size = self._attributes.get(attribute)
+ if size:
+ size = string_to_type(size)
+
+ return size

Still in checkbox.lib.dmi, you added:

+ @property
+ def form(self):
+ attribute = "%s_form" % self.category.lower()
+ form = self._attributes.get(attribute)
+
+ if form:
+ return form
+
+ return None

This could be expressed more simply as:

+ @property
+ def form(self):
+ attribute = "%s_form" % self.category.lower()
+ return self._attributes.get(attribute)

Other than that, the changes look good. After you make these changes, I'll have another look but I think we'll be good to merge. Thanks!

review: Needs Fixing
1481. By Brendan Donegan

Implemented cr3's suggestions.

Revision history for this message
Brendan Donegan (brendan-donegan) wrote :

Okay, thanks for pointing out the string_to_type function - very useful! I've implemented these suggestions pretty much verbatim, so I guess we're done here!

review: Needs Resubmitting
Revision history for this message
Marc Tardif (cr3) wrote :

Nice, thanks for improving checkbox.parsers!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'checkbox/lib/dmi.py'
2--- checkbox/lib/dmi.py 2011-10-11 20:15:01 +0000
3+++ checkbox/lib/dmi.py 2012-07-03 18:18:18 +0000
4@@ -18,6 +18,7 @@
5 #
6 import os
7
8+from checkbox.lib.conversion import string_to_type
9
10 # See also 3.3.4.1 of the "System Management BIOS Reference Specification,
11 # Version 2.6.1" (Preliminary Standard) document, available from
12@@ -223,3 +224,18 @@
13 return version
14
15 return None
16+
17+ @property
18+ def size(self):
19+ attribute = "%s_size" % self.category.lower()
20+ size = self._attributes.get(attribute)
21+
22+ if size:
23+ size = string_to_type(size)
24+
25+ return size
26+
27+ @property
28+ def form(self):
29+ attribute = "%s_form" % self.category.lower()
30+ return self._attributes.get(attribute)
31
32=== modified file 'checkbox/parsers/dmidecode.py'
33--- checkbox/parsers/dmidecode.py 2012-06-01 13:57:25 +0000
34+++ checkbox/parsers/dmidecode.py 2012-07-03 18:18:18 +0000
35@@ -50,6 +50,8 @@
36 "Type": "type",
37 "Vendor": "vendor",
38 "Version": "version",
39+ "Size": "size",
40+ "Form Factor": "form",
41 }
42
43 def __init__(self, stream):
44@@ -97,11 +99,12 @@
45 category = Dmi.type_names[type_index]
46 category = category.upper().split(" ")[-1]
47 if category not in (
48- "BOARD", "BIOS", "CHASSIS", "PROCESSOR", "SYSTEM"):
49+ "BOARD", "BIOS", "CHASSIS", "DEVICE", "PROCESSOR", "SYSTEM"):
50 continue
51
52 # Parse attributes
53 attributes = {}
54+
55 for line in lines:
56 # Skip lines with an unsupported key/value pair
57 match = KEY_VALUE_RE.match(line)
58
59=== modified file 'debian/changelog'
60--- debian/changelog 2012-07-03 15:19:26 +0000
61+++ debian/changelog 2012-07-03 18:18:18 +0000
62@@ -18,7 +18,16 @@
63 * Added a message file format test that does some simplistic checks
64 on jobs/* files to ensure they are sane.
65
66+<<<<<<< TREE
67 -- Jeff Lane <jeff@ubuntu.com> Fri, 29 Jun 2012 16:30:33 -0400
68+=======
69+ [Brendan Donegan]
70+ * Reimplemented memory_compare in python3 and restructured it to put
71+ things into dictionaries for easy access. Also fixed bug with detecting
72+ non-RAM devices as RAM. (LP: #960087)
73+
74+ -- Jeff Lane <jeff@ubuntu.com> Fri, 29 Jun 2012 15:46:37 -0400
75+>>>>>>> MERGE-SOURCE
76
77 checkbox (0.14.1) quantal; urgency=low
78
79
80=== modified file 'scripts/dmi_resource'
81--- scripts/dmi_resource 2012-05-31 20:21:08 +0000
82+++ scripts/dmi_resource 2012-07-03 18:18:18 +0000
83@@ -30,11 +30,11 @@
84 class DmiResult:
85
86 attributes = ("path", "category", "product", "vendor", "serial",
87- "version",)
88+ "version", "size", "form",)
89
90 def addDmiDevice(self, device):
91 for attribute in self.attributes:
92- value = getattr(device, attribute)
93+ value = getattr(device, attribute, None)
94 if value is not None:
95 print("%s: %s" % (attribute, value))
96
97@@ -43,10 +43,10 @@
98
99 def main():
100 stream = os.popen(COMMAND)
101- udev = DmidecodeParser(stream)
102+ dmi = DmidecodeParser(stream)
103
104 result = DmiResult()
105- udev.run(result)
106+ dmi.run(result)
107
108 return 0
109
110
111=== modified file 'scripts/memory_compare'
112--- scripts/memory_compare 2012-02-02 17:24:06 +0000
113+++ scripts/memory_compare 2012-07-03 18:18:18 +0000
114@@ -1,27 +1,70 @@
115-#!/bin/bash
116-
117-MIN_LEVEL=90
118-
119-meminfo_total=`grep 'MemTotal' /proc/meminfo | awk '{print $2}'`
120-meminfo_units=`grep 'MemTotal' /proc/meminfo | awk '{print $3}'`
121-
122-echo "Meminfo total: $meminfo_total $meminfo_units"
123-
124-dmi_total=0
125-
126-for size in `dmidecode -t 17 | grep Size | grep -o [0-9]*`
127-do
128- dmi_total=`echo $dmi_total + $size | bc`
129-done
130-
131-dmi_total=`echo "$dmi_total * 1000" | bc`
132-
133-echo "DMI total: $dmi_total $meminfo_units"
134-accuracy=`echo "scale=2; $meminfo_total / $dmi_total * 100" | bc`
135-echo "Accuracy: $accuracy"
136-
137-if [ ${accuracy::-3} -lt $MIN_LEVEL ]
138-then
139- echo "Memory totals not close enough"
140- exit 1
141-fi
142+#!/usr/bin/env python3
143+
144+import os
145+import sys
146+
147+from checkbox.parsers.dmidecode import DmidecodeParser
148+from checkbox.parsers.meminfo import MeminfoParser
149+
150+THRESHOLD = 10
151+
152+class DmiResult:
153+
154+ total_size = 0
155+ form = None
156+
157+ def addDmiDevice(self, device):
158+ size = getattr(device, "size", None)
159+ form = getattr(device, "form", None)
160+
161+ if form and "IMM" in form:
162+ self.form = form
163+
164+ if size:
165+ self.total_size += size
166+
167+def get_installed_memory_size():
168+ dmi = DmidecodeParser(os.popen('dmidecode'))
169+ result = DmiResult()
170+
171+ dmi.run(result)
172+
173+ return result.total_size
174+
175+class MeminfoResult:
176+
177+ memtotal = 0
178+
179+ def setMemory(self, memory):
180+ self.memtotal = memory['total']
181+
182+def get_visible_memory_size():
183+ parser = MeminfoParser(open('/proc/meminfo'))
184+ result = MeminfoResult()
185+ parser.run(result)
186+
187+ return result.memtotal
188+
189+def main():
190+ if os.geteuid() != 0:
191+ print("This script must be run as root.")
192+ return 1
193+
194+ installed_memory = get_installed_memory_size()
195+ print("Installed memory: %d kB" % installed_memory)
196+
197+ visible_memory = get_visible_memory_size()
198+ print("Visible memory: %d kB" % visible_memory)
199+
200+ difference = installed_memory - visible_memory
201+ percentage = difference / installed_memory * 100
202+
203+ if percentage <= THRESHOLD:
204+ print("Difference is %d bytes (%.2f%%) and less than the %d%% threshold." % (difference, percentage, THRESHOLD))
205+ return 0
206+ else:
207+ print("Difference is %d bytes (%.2f%%) and greater than the %d%% threshold." % (difference, percentage, THRESHOLD))
208+ return 1
209+
210+if __name__ == "__main__":
211+ sys.exit(main())

Subscribers

People subscribed via source and target branches