11# This file is part of cloud-init. See LICENSE file for license information.
22from cloudinit import log as logging
33from cloudinit import subp
4- from cloudinit .util import is_container
4+ from cloudinit .util import is_container , is_FreeBSD
55
6+ from collections import namedtuple
67import os
78
89LOG = logging .getLogger (__name__ )
910
1011# Path for DMI Data
1112DMI_SYS_PATH = "/sys/class/dmi/id"
1213
13- # dmidecode and /sys/class/dmi/id/* use different names for the same value,
14- # this allows us to refer to them by one canonical name
15- DMIDECODE_TO_DMI_SYS_MAPPING = {
16- 'baseboard-asset-tag' : 'board_asset_tag' ,
17- 'baseboard-manufacturer' : 'board_vendor' ,
18- 'baseboard-product-name' : 'board_name' ,
19- 'baseboard-serial-number' : 'board_serial' ,
20- 'baseboard-version' : 'board_version' ,
21- 'bios-release-date' : 'bios_date' ,
22- 'bios-vendor' : 'bios_vendor' ,
23- 'bios-version' : 'bios_version' ,
24- 'chassis-asset-tag' : 'chassis_asset_tag' ,
25- 'chassis-manufacturer' : 'chassis_vendor' ,
26- 'chassis-serial-number' : 'chassis_serial' ,
27- 'chassis-version' : 'chassis_version' ,
28- 'system-manufacturer' : 'sys_vendor' ,
29- 'system-product-name' : 'product_name' ,
30- 'system-serial-number' : 'product_serial' ,
31- 'system-uuid' : 'product_uuid' ,
32- 'system-version' : 'product_version' ,
14+ kdmi = namedtuple ('KernelNames' , ['linux' , 'freebsd' ])
15+ kdmi .__new__ .defaults__ = (None , None )
16+
17+ # FreeBSD's kenv(1) and Linux /sys/class/dmi/id/* both use different names from
18+ # dmidecode. The values are the same, and ultimately what we're interested in.
19+ # These tools offer a "cheaper" way to access those values over dmidecode.
20+ # This is our canonical translation table. If we add more tools on other
21+ # platforms to find dmidecode's values, their keys need to be put in here.
22+ DMIDECODE_TO_KERNEL = {
23+ 'baseboard-asset-tag' : kdmi ('board_asset_tag' , 'smbios.planar.tag' ),
24+ 'baseboard-manufacturer' : kdmi ('board_vendor' , 'smbios.planar.maker' ),
25+ 'baseboard-product-name' : kdmi ('board_name' , 'smbios.planar.product' ),
26+ 'baseboard-serial-number' : kdmi ('board_serial' , 'smbios.planar.serial' ),
27+ 'baseboard-version' : kdmi ('board_version' , 'smbios.planar.version' ),
28+ 'bios-release-date' : kdmi ('bios_date' , 'smbios.bios.reldate' ),
29+ 'bios-vendor' : kdmi ('bios_vendor' , 'smbios.bios.vendor' ),
30+ 'bios-version' : kdmi ('bios_version' , 'smbios.bios.version' ),
31+ 'chassis-asset-tag' : kdmi ('chassis_asset_tag' , 'smbios.chassis.tag' ),
32+ 'chassis-manufacturer' : kdmi ('chassis_vendor' , 'smbios.chassis.maker' ),
33+ 'chassis-serial-number' : kdmi ('chassis_serial' , 'smbios.chassis.serial' ),
34+ 'chassis-version' : kdmi ('chassis_version' , 'smbios.chassis.version' ),
35+ 'system-manufacturer' : kdmi ('sys_vendor' , 'smbios.system.maker' ),
36+ 'system-product-name' : kdmi ('product_name' , 'smbios.system.product' ),
37+ 'system-serial-number' : kdmi ('product_serial' , 'smbios.system.serial' ),
38+ 'system-uuid' : kdmi ('product_uuid' , 'smbios.system.uuid' ),
39+ 'system-version' : kdmi ('product_version' , 'smbios.system.version' ),
3340}
3441
3542
3643def _read_dmi_syspath (key ):
3744 """
38- Reads dmi data with from /sys/class/dmi/id
45+ Reads dmi data from /sys/class/dmi/id
3946 """
40- if key not in DMIDECODE_TO_DMI_SYS_MAPPING :
47+ kmap = DMIDECODE_TO_KERNEL .get (key )
48+ if kmap is None or kmap .linux is None :
4149 return None
42- mapped_key = DMIDECODE_TO_DMI_SYS_MAPPING [key ]
43- dmi_key_path = "{0}/{1}" .format (DMI_SYS_PATH , mapped_key )
44-
50+ dmi_key_path = "{0}/{1}" .format (DMI_SYS_PATH , kmap .linux )
4551 LOG .debug ("querying dmi data %s" , dmi_key_path )
4652 if not os .path .exists (dmi_key_path ):
4753 LOG .debug ("did not find %s" , dmi_key_path )
@@ -68,6 +74,29 @@ def _read_dmi_syspath(key):
6874 return None
6975
7076
77+ def _read_kenv (key ):
78+ """
79+ Reads dmi data from FreeBSD's kenv(1)
80+ """
81+ kmap = DMIDECODE_TO_KERNEL .get (key )
82+ if kmap is None or kmap .freebsd is None :
83+ return None
84+
85+ LOG .debug ("querying dmi data %s" , kmap .freebsd )
86+
87+ try :
88+ cmd = ["kenv" , "-q" , kmap .freebsd ]
89+ (result , _err ) = subp .subp (cmd )
90+ result = result .strip ()
91+ LOG .debug ("kenv returned '%s' for '%s'" , result , kmap .freebsd )
92+ return result
93+ except subp .ProcessExecutionError as e :
94+ LOG .debug ('failed kenv cmd: %s\n %s' , cmd , e )
95+ return None
96+
97+ return None
98+
99+
71100def _call_dmidecode (key , dmidecode_path ):
72101 """
73102 Calls out to dmidecode to get the data out. This is mostly for supporting
@@ -81,7 +110,7 @@ def _call_dmidecode(key, dmidecode_path):
81110 if result .replace ("." , "" ) == "" :
82111 return ""
83112 return result
84- except ( IOError , OSError ) as e :
113+ except subp . ProcessExecutionError as e :
85114 LOG .debug ('failed dmidecode cmd: %s\n %s' , cmd , e )
86115 return None
87116
@@ -107,6 +136,9 @@ def read_dmi_data(key):
107136 if is_container ():
108137 return None
109138
139+ if is_FreeBSD ():
140+ return _read_kenv (key )
141+
110142 syspath_value = _read_dmi_syspath (key )
111143 if syspath_value is not None :
112144 return syspath_value
0 commit comments