summaryrefslogtreecommitdiff
path: root/bin/dmitest
diff options
authorSylvain Pineau <sylvain.pineau@canonical.com>2016-10-07 09:48:55 +0200
committerSylvain Pineau <sylvain.pineau@canonical.com>2016-10-07 09:48:55 +0200
commit33a440473829a82188a9547146789fae72185c5e (patch)
treeaa8efa1434f252432ab99274eaca45a9427207bc /bin/dmitest
parentcbbe2fe63a1b22f6d0873bfe11ff3e834a1a883c (diff)
Import plainbox-provider-checkbox_0.21.orig.tar.gzupstream-0.21patched-0.21-1
Diffstat (limited to 'bin/dmitest')
-rwxr-xr-xbin/dmitest230
1 files changed, 230 insertions, 0 deletions
diff --git a/bin/dmitest b/bin/dmitest
new file mode 100755
index 0000000..02e67a9
--- /dev/null
+++ b/bin/dmitest
@@ -0,0 +1,230 @@
+#!/usr/bin/env python3
+#
+# This file is part of Checkbox.
+#
+# Copyright 2014 Canonical Ltd.
+#
+# Checkbox is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3,
+# as published by the Free Software Foundation.
+#
+# Checkbox is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
+#
+# Test for sane dmidecode output, particularly with respect to
+# various manufacturer information fields. Also, verify that the
+# system reports a chassis type that suits its class (server or
+# desktop/laptop)
+#
+# By: Rod Smith
+#
+# Parameters:
+# * --dmifile {filename} -- Input filename; optional. If specified,
+# file is used instead of dmidecode output.
+# * --test_versions -- Include chassis, system, and base boad version
+# numbers among tests.
+# * --test_serials -- Include system and base board serial numbers among
+# tests.
+# * 'desktop' or 'server' -- Type of system being tested.
+
+import re
+import subprocess
+import sys
+
+from argparse import ArgumentParser
+
+# Command to retrieve DMI information
+COMMAND = "dmidecode"
+
+
+def find_in_section(stream, section, label, strings, find_empty):
+ """ Search for a set of strings on a labelled line in a section
+ of the output.
+ :param stream:
+ input text stream (dmidecode output)
+ :param section:
+ section label in which to search (e.g., "Chassis Information")
+ :param label:
+ label of line on which to search (e.g., "Type:")
+ :param strings:
+ set of strings for which to search (e.g., ["server", "blade"])
+ :param find_empty:
+ if True, matches empty label field (as if '""' were passed as
+ a strings value)
+ :returns found:
+ True if one or more of strings was found on "label" line in "section"
+ section, or if "label" line is empty AND find_empty is True;
+ False otherwise
+ """
+ start_looking = False
+ found = False
+ empty = True
+ for line in stream:
+ if line == section:
+ start_looking = True
+ if start_looking and re.search(label, line):
+ print("\n" + section)
+ print(line.strip())
+ empty = len(line.strip()) == len(label)
+ if empty and find_empty:
+ found = True
+ for s in strings:
+ if re.search(s, line, flags=re.IGNORECASE):
+ found = True
+ break
+ start_looking = False
+
+ return found
+
+
+def main():
+ parser = ArgumentParser("dmitest")
+ parser.add_argument('system_type',
+ help="System type ('server' or 'desktop').",
+ choices=['server', 'desktop'])
+ parser.add_argument('--dmifile',
+ help="File to use in lieu of dmidecode.")
+ parser.add_argument('--test_versions', action="store_true",
+ help="Set to check version information")
+ parser.add_argument('--test_serials', action="store_true",
+ help="Set to check serial number information")
+ args = parser.parse_args()
+
+ try:
+ if args.dmifile:
+ print("Reading " + args.dmifile + " as DMI data")
+ stream = subprocess.check_output(['cat', args.dmifile], universal_newlines=True).splitlines()
+ else:
+ stream = subprocess.check_output(COMMAND, universal_newlines=True).splitlines()
+ except subprocess.CalledProcessError as err:
+ print("Error running {}: {}".format(COMMAND, err))
+ return 1
+
+ retval = 0
+
+ """
+ NOTE: System type is encoded in both the "Chassis Information" and "Base
+ Board Type" sections. The former is more reliable, so we do a whitelist
+ test on it -- the type MUST be specified correctly. The "Base Board Type"
+ section is less reliable, so rather than flag large numbers of systems
+ for having "Unknown", "Other", or something similar here, we just flag
+ it when it's at odds with the type passed on the command line. Also,
+ the "Base Board Type" may specify a desktop or tower system on servers
+ shipped in those form factors, so we don't flag that combination as an
+ error.
+ """
+ if args.system_type == 'server':
+ if not find_in_section(stream, 'Chassis Information', 'Type:',
+ ['server', 'rack mount', 'blade',
+ 'expansion chassis', 'multi-system'], False):
+ print("*** Incorrect or unknown server chassis type!")
+ retval = 1
+ if find_in_section(stream, 'Base Board Information', 'Type:',
+ ['portable', 'notebook', 'space-saving',
+ 'all in one'], False):
+ print("*** Incorrect server base board type!")
+ retval = 1
+ else:
+ if not find_in_section(stream, 'Chassis Information', 'Type:',
+ ['notebook', 'portable', 'laptop', 'desktop',
+ 'lunch box', 'space-saving', 'tower',
+ 'all in one', 'hand held'], False):
+ print("*** Incorrect or unknown desktop chassis type!")
+ retval = 1
+ if find_in_section(stream, 'Base Board Information', 'Type:',
+ ['rack mount', 'server', 'multi-system',
+ 'interconnect board'], False):
+ print("*** Incorrect desktop base board type!")
+ retval = 1
+
+ if find_in_section(stream, 'Chassis Information', 'Manufacturer:',
+ ['empty', 'chassis manufacture', 'null', 'insyde',
+ 'to be filled by o\.e\.m\.', 'no enclosure',
+ '\.\.\.\.\.'], True):
+ print("*** Invalid chassis manufacturer!")
+ retval = 1
+
+ if find_in_section(stream, 'System Information', 'Manufacturer:',
+ ['system manufacture', 'insyde', 'standard',
+ 'to be filled by o\.e\.m\.', 'no enclosure'], True):
+ print("*** Invalid system manufacturer!")
+ retval = 1
+
+ if find_in_section(stream, 'Base Board Information', 'Manufacturer:',
+ ['to be filled by o\.e\.m\.'], True):
+ print("*** Invalid base board manufacturer!")
+ retval = 1
+
+ if find_in_section(stream, 'System Information', 'Product Name:',
+ ['system product name', 'to be filled by o\.e\.m\.'],
+ False):
+ print("*** Invalid system product name!")
+ retval = 1
+
+ if find_in_section(stream, 'Base Board Information', 'Product Name:',
+ ['base board product name',
+ 'to be filled by o\.e\.m\.'], False):
+ print("*** Invalid base board product name!")
+ retval = 1
+
+ if args.test_versions:
+
+ if find_in_section(stream, 'Chassis Information', 'Version:',
+ ['to be filled by o\.e\.m\.', 'empty'],
+ False):
+ print("*** Invalid chassis version!")
+ retval = 1
+
+ if find_in_section(stream, 'System Information', 'Version:',
+ ['to be filled by o\.e\.m\.', '\(none\)',
+ 'null', 'system version', 'not applicable',
+ '\.\.\.\.\.'], False):
+ print("*** Invalid system information version!")
+ retval = 1
+
+ if find_in_section(stream, 'Base Board Information', 'Version:',
+ ['base board version',
+ 'empty', 'to be filled by o\.e\.m\.'], False):
+ print("*** Invalid base board version!")
+ retval = 1
+
+ if args.test_serials:
+
+ if find_in_section(stream, 'System Information', 'Serial Number:',
+ ['to be filled by o\.e\.m\.',
+ 'system serial number', '\.\.\.\.\.'],
+ False):
+ print("*** Invalid system information serial number!")
+ retval = 1
+
+ if find_in_section(stream, 'Base Board Information', 'Serial Number:',
+ ['n/a', 'base board serial number',
+ 'to be filled by o\.e\.m\.', 'empty', '\.\.\.'],
+ False):
+ print("*** Invalid base board serial number!")
+ retval = 1
+
+ if find_in_section(stream, 'Processor Information', 'Version:',
+ ['sample'], False):
+ print("*** Invalid processor information!")
+ retval = 1
+
+ # In review of dmidecode data on 10/23/2014, no conspicuous problems
+ # found in BIOS Information section's Vendor, Version, or Release Date
+ # fields. Therefore, no tests based on these fields have been written.
+
+ if retval:
+ print("\nFailed one or more tests (see above)")
+ else:
+ print("\nPassed all tests")
+
+ return retval
+
+
+if __name__ == "__main__":
+ sys.exit(main())