summaryrefslogtreecommitdiff
diff options
-rwxr-xr-xbin/system_info.py232
1 files changed, 232 insertions, 0 deletions
diff --git a/bin/system_info.py b/bin/system_info.py
new file mode 100755
index 0000000..55452d8
--- /dev/null
+++ b/bin/system_info.py
@@ -0,0 +1,232 @@
+#!/usr/bin/env python3
+# encoding: UTF-8
+# Copyright (c) 2018 Canonical Ltd.
+#
+# Authors:
+# Sylvain Pineau <sylvain.pineau@canonical.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+from collections import OrderedDict
+import json
+import re
+import subprocess
+
+
+def _run_cmd(cmd):
+ try:
+ return subprocess.check_output(
+ cmd, shell=True, universal_newlines=True)
+ except subprocess.CalledProcessError:
+ return None
+
+
+class INXI:
+ """
+ INXI JSON wrapper
+ """
+
+ def __init__(self, inxi_output):
+ self._inxi = {}
+ if inxi_output:
+ self._inxi = inxi_output
+ self._system_info = OrderedDict()
+
+ def _find_section(self, key):
+ for k, v in self._inxi.items():
+ if key in k:
+ return self._inxi[k]
+ else:
+ return []
+
+ def _find_records(self, section, key):
+ records = []
+ for record in section:
+ for k in record.keys():
+ if key in k:
+ records.append(OrderedDict(sorted(record.items())))
+ return records
+
+ def _prepare_system_info(self):
+ system_data = []
+ system = self._find_section('System')
+ system_info = self._find_records(system, '#Kernel')
+ system_details = ''
+ for i in system_info:
+ for k, v in i.items():
+ if '#Kernel' in k:
+ system_details += '{}: {}\n'.format(
+ re.sub('.*#', '', k), v)
+ elif '#Distro' in k:
+ system_details += '{}: {}'.format(re.sub('.*#', '', k), v)
+ if system_details:
+ system_data = system_details.splitlines()
+ if system_data:
+ self._system_info['System'] = system_data
+
+ def _prepare_machine_info(self):
+ machine_data = []
+ machine = self._find_section('Machine')
+ machine_info = self._find_records(machine, '#Type')
+ machine_details = ''
+ for i in machine_info:
+ for k, v in i.items():
+ if '#serial' in k:
+ break
+ elif '#product' in k:
+ machine_details += '\n'
+ machine_details += '{}: {} '.format(re.sub('.*#', '', k), v)
+ if machine_details:
+ machine_data = machine_details.splitlines()
+ machine_info = self._find_records(machine, '#UEFI')
+ machine_UEFI = ''
+ for i in machine_info:
+ keep = False
+ for k, v in i.items():
+ if '#UEFI' in k:
+ keep = True
+ if not keep:
+ continue
+ machine_UEFI += '{}: {} '.format(re.sub('.*#', '', k), v)
+ if machine_UEFI:
+ machine_data.append(machine_UEFI)
+ if machine_data:
+ self._system_info['Machine'] = machine_data
+
+ def _prepare_cpu_info(self):
+ cpu_data = []
+ cpu = self._find_section('CPU')
+ cpu_info = self._find_records(cpu, '#Topology')
+ cpu_details = ''
+ for i in cpu_info:
+ for k, v in i.items():
+ if '#bits' in k or '#type' in k:
+ continue
+ elif '#model' in k:
+ cpu_details += '\nModel: {} '.format(v)
+ else:
+ cpu_details += '{}: {} '.format(re.sub('.*#', '', k), v)
+ if '#arch' in k:
+ break
+ if cpu_details:
+ cpu_data = cpu_details.splitlines()
+ if cpu_data:
+ self._system_info['CPU'] = cpu_data
+
+ def _prepare_memory_info(self):
+ memory_data = []
+ memory = self._find_section('Memory')
+ memory_info = self._find_records(memory, '#total')
+ memory_details = ''
+ for i in memory_info:
+ for k, v in i.items():
+ if '#total' in k:
+ memory_details += v
+ break
+ if memory_details:
+ memory_data.append(memory_details)
+ if memory_data:
+ self._system_info['Memory'] = memory_data
+
+ def _prepare_generic_info(self, section_name, key):
+ generic_data = []
+ generic = self._find_section(section_name)
+ generic_info = self._find_records(generic, key)
+ for i in generic_info:
+ generic_details = ''
+ ignore = False
+ device_mode = False
+ for k, v in i.items():
+ # Ignore USB/removable devices (except Network)
+ if '#type' in k and section_name != 'Network':
+ ignore = True
+ if key in k and '#ID' not in k:
+ generic_details += v
+ device_mode = True
+ if (
+ not device_mode and
+ ('#vendor' in k or '#model' in k or '#size' in k)
+ ):
+ generic_details += '{} '.format(v)
+ if '#chip ID' in k:
+ generic_details += ' [{}]'.format(v)
+ if generic_details and not ignore:
+ generic_data.append(generic_details)
+ if generic_data:
+ self._system_info[section_name] = generic_data
+
+ def _prepare_raid_info(self):
+ raid_data = []
+ raid = self._find_section('RAID')
+ raid_info = self._find_records(raid, '#Hardware')
+ for i in raid_info:
+ raid_details = ''
+ for k, v in i.items():
+ if '#Hardware' in k:
+ raid_details += v
+ if '#chip ID' in k:
+ raid_details += ' [{}]'.format(v)
+ if raid_details:
+ raid_data.append(raid_details)
+ if raid_data:
+ self._system_info['RAID'] = raid_data
+ raid_info = self._find_records(raid, '#Device')
+ for i in raid_info:
+ raid_details = ''
+ for k, v in i.items():
+ if '#Device' in k:
+ raid_details += v
+ if '#type' in k:
+ raid_details += ' {}: {} '.format(re.sub('.*#', '', k), v)
+ if raid_details:
+ raid_data.append(raid_details)
+ if raid_data:
+ self._system_info['RAID'] = raid_data
+
+ def get_sys_info(self):
+ self._prepare_system_info()
+ self._prepare_machine_info()
+ self._prepare_cpu_info()
+ self._prepare_memory_info()
+ self._prepare_generic_info('Audio', '#Device')
+ self._prepare_generic_info('Graphics', '#Device')
+ self._prepare_generic_info('Network', '#Device')
+ self._prepare_generic_info('Drives', '#ID')
+ self._prepare_raid_info()
+ return self._system_info
+
+
+def main():
+ inxi_output = _run_cmd(
+ "inxi_snapshot -A -G -C -M -m -N -D -S -R -xx "
+ "--output json --output-file print")
+ if not inxi_output:
+ inxi_output = '{}'
+ inxi = INXI(json.loads(inxi_output))
+ sys_info = inxi.get_sys_info()
+ extra_sections = {
+ 'Bluetooth': 'BLUETOOTH',
+ 'Touchscreen': 'TOUCHSCREEN',
+ 'Webcam': 'CAPTURE',
+ 'Touchpad': 'TOUCHPAD'
+ }
+ for section, udev_category in extra_sections.items():
+ section_info = _run_cmd('udev_resource -l {} -s'.format(udev_category))
+ if section_info:
+ sys_info[section] = section_info.splitlines()
+ print(json.dumps(sys_info, indent=4))
+
+
+if __name__ == '__main__':
+ raise SystemExit(main())