Merge lp:~mpontillo/maas/commissioning-dmi-data into lp:~maas-committers/maas/trunk

Proposed by Mike Pontillo
Status: Rejected
Rejected by: MAAS Lander
Proposed branch: lp:~mpontillo/maas/commissioning-dmi-data
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 199 lines (+130/-4)
2 files modified
src/metadataserver/models/commissioningscript.py (+67/-1)
src/provisioningserver/refresh/node_info_scripts.py (+63/-3)
To merge this branch: bzr merge lp:~mpontillo/maas/commissioning-dmi-data
Reviewer Review Type Date Requested Status
MAAS Maintainers Pending
Review via email: mp+318303@code.launchpad.net

Commit message

Read DMI data during commissioning, for future interpretation.

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

Transitioned to Git.

lp:maas has now moved from Bzr to Git.
Please propose your branches with Launchpad using Git.

git clone https://git.launchpad.net/maas

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/metadataserver/models/commissioningscript.py'
2--- src/metadataserver/models/commissioningscript.py 2017-01-28 00:51:47 +0000
3+++ src/metadataserver/models/commissioningscript.py 2017-02-25 10:53:07 +0000
4@@ -3,12 +3,13 @@
5
6 """Custom commissioning scripts, and their database backing."""
7
8-
9 __all__ = [
10 'NODE_INFO_SCRIPTS',
11 'CommissioningScript',
12 ]
13
14+from collections import OrderedDict
15+import fnmatch
16 import json
17 import logging
18 import math
19@@ -24,9 +25,11 @@
20 from maasserver.models.interface import PhysicalInterface
21 from maasserver.models.physicalblockdevice import PhysicalBlockDevice
22 from maasserver.models.tag import Tag
23+from maasserver.third_party_drivers import node_modaliases
24 from metadataserver import DefaultMeta
25 from metadataserver.fields import BinaryField
26 from provisioningserver.refresh.node_info_scripts import (
27+ DMIDECODE_OUTPUT_NAME,
28 LSHW_OUTPUT_NAME,
29 NODE_INFO_SCRIPTS,
30 )
31@@ -367,12 +370,75 @@
32 id__in=delete_block_device_ids).delete()
33
34
35+SWITCH_ASIC_HYPOTHESES = OrderedDict([
36+ ('pci:v000014E4d0000B850sv000014E4sd0000B850bc02sc00i00', 'wedge40'),
37+ ('pci:v000014E4d0000B960sv000014E4sd0000B960bc02sc00i00', 'wedge100'),
38+])
39+
40+
41+def parse_dmidecode_output(script_result: bytes):
42+ KEYS_START = '-----BEGIN DMI KEYPAIRS-----'
43+ KEYS_END = '-----END DMI KEYPAIRS-----'
44+ output = script_result.decode('utf-8')
45+ scan_keypair = False
46+ dmi_data = {}
47+ for line in output.splitlines():
48+ # Change parser state depending on where we are in the file.
49+ if line.startswith('-----') and line.strip() == KEYS_START:
50+ scan_keypair = True
51+ continue
52+ if line.startswith('-----') and line.strip() == KEYS_END:
53+ scan_keypair = False
54+ continue
55+ if scan_keypair:
56+ kvp = line.split('=', maxsplit=1)
57+ if len(kvp) == 2:
58+ key, value = kvp
59+ dmi_data[key] = value.strip()
60+ else:
61+ logger.warning("Malformed DMI key=value pair: '%s'" % line)
62+ return dmi_data
63+
64+
65+def correlate_dmidecode_details_with_detected_hardware(
66+ node, output, exit_status):
67+ modaliases = node_modaliases(node)
68+ found_switch = False
69+ possibilities = []
70+ for alias, hypothesis in SWITCH_ASIC_HYPOTHESES:
71+ matches = fnmatch.filter(modaliases, alias)
72+ if len(matches) > 0:
73+ # Found a known switch ASIC, so add the 'switch' tag.
74+ found_switch = True
75+ possibilities.add(hypothesis)
76+ if found_switch:
77+ switch, _ = Tag.objects.get_or_create(name='switch')
78+ from pprint import pprint
79+ # XXX: Temporary debug code to print the DMI data we found.
80+ pprint({
81+ "hostname": node.hostname,
82+ "modaliases": modaliases,
83+ "dmidecode_output": output,
84+ "status": exit_status,
85+ "dmi_data": parse_dmidecode_output(output)
86+ })
87+ # XXX: Should we store the dmi_data somewhere? (Future branch.)
88+ # XXX: If more than one possibility matched, narrow it down.
89+ if len(possibilities) == 1:
90+ # Narrowed it down to one possible device type we care about, so
91+ # let's get it tagged!
92+ model_string = possibilities[0]
93+ model, _ = Tag.objects.get_or_create(name=model_string)
94+
95 # Register the post processing hooks.
96 NODE_INFO_SCRIPTS[LSHW_OUTPUT_NAME]['hook'] = update_hardware_details
97 NODE_INFO_SCRIPTS['00-maas-01-cpuinfo']['hook'] = parse_cpuinfo
98 NODE_INFO_SCRIPTS['00-maas-02-virtuality']['hook'] = set_virtual_tag
99 NODE_INFO_SCRIPTS['00-maas-07-block-devices']['hook'] = (
100 update_node_physical_block_devices)
101+NODE_INFO_SCRIPTS[DMIDECODE_OUTPUT_NAME]['hook'] = (
102+ correlate_dmidecode_details_with_detected_hardware
103+)
104 NODE_INFO_SCRIPTS['99-maas-03-network-interfaces']['hook'] = (
105 update_node_network_information)
106 NODE_INFO_SCRIPTS['99-maas-04-network-interfaces-with-sriov']['hook'] = (
107
108=== modified file 'src/provisioningserver/refresh/node_info_scripts.py'
109--- src/provisioningserver/refresh/node_info_scripts.py 2017-02-17 14:23:04 +0000
110+++ src/provisioningserver/refresh/node_info_scripts.py 2017-02-25 10:53:07 +0000
111@@ -16,11 +16,11 @@
112 import os
113 from textwrap import dedent
114
115-# Name of the file where the node info scripts store lshw output.
116+# Well-known commissioning script names. (Used for locating commissioning
117+# script output.)
118 LSHW_OUTPUT_NAME = '00-maas-01-lshw'
119-
120-# Name of the file where the node info scripts store LLDP output.
121 LLDP_OUTPUT_NAME = '99-maas-02-capture-lldp'
122+DMIDECODE_OUTPUT_NAME = '00-maas-08-dmidecode'
123
124
125 def make_function_call_script(function, *args, **kwargs):
126@@ -108,6 +108,59 @@
127 done
128 """)
129
130+DMIDECODE_SCRIPT = dedent("""\
131+ #!/bin/bash
132+
133+ OUTFILE=/root/dmi.bin
134+
135+ # Some platforms won't be able to dump the DMI data (such as non-Intel), so
136+ # exit gracefully if this fails.
137+ dmidecode -u --dump-bin $OUTFILE && (
138+ echo "-----BEGIN DMI DATA-----" ;
139+ base64 $OUTFILE
140+ echo "-----END DMI DATA-----"
141+ ) || (echo "Unable to read DMI information."; exit 0)
142+
143+ echo ""
144+ echo "-----BEGIN FULL DMI DECODE-----"
145+ dmidecode -u --from-dump $OUTFILE
146+ echo "-----END FULL DMI DECODE-----"
147+
148+ # See http://git.savannah.nongnu.org/cgit/dmidecode.git/tree/dmiopt.c#n142
149+ DMI_STRINGS="
150+ bios-vendor
151+ bios-version
152+ bios-release-date
153+ system-manufacturer
154+ system-product-name
155+ system-version
156+ system-serial-number
157+ system-uuid
158+ baseboard-manufacturer
159+ baseboard-product-name
160+ baseboard-version
161+ baseboard-serial-number
162+ baseboard-asset-tag
163+ chassis-manufacturer
164+ chassis-type
165+ chassis-version
166+ chassis-serial-number
167+ chassis-asset-tag
168+ processor-family
169+ processor-manufacturer
170+ processor-version
171+ processor-frequency
172+ "
173+
174+ echo ""
175+ echo "-----BEGIN DMI KEYPAIRS-----"
176+ for key in $DMI_STRINGS; do
177+ value=$(dmidecode --from-dump $OUTFILE -s $key)
178+ printf "%s=%s\\n" "$key" "$(echo $value | tr '\\n' ' ')"
179+ done
180+ echo "-----END DMI KEYPAIRS-----"
181+ """)
182+
183
184 # Run `dhclient` on all the unconfigured interfaces.
185 # This is done to create records in the leases file for the
186@@ -429,6 +482,13 @@
187 'hook': null_hook,
188 'run_on_controller': True,
189 }),
190+ (DMIDECODE_OUTPUT_NAME, {
191+ 'content': DMIDECODE_SCRIPT.encode('ascii'),
192+ 'hook': null_hook,
193+ # Note: while it would be nice to run this on the controller, dmidecode
194+ # requires root priveleges, so it's not currently useful.
195+ 'run_on_controller': False,
196+ }),
197 ('99-maas-01-wait-for-lldpd', {
198 'content': make_function_call_script(
199 lldpd_wait, "/var/run/lldpd.socket", time_delay=60),