From a0d820972c1ace2e61a145da40efcc2699f791a7 Mon Sep 17 00:00:00 2001 From: Andreas Thienemann Date: Fri, 9 Mar 2018 10:52:16 +0100 Subject: [PATCH 1/6] New grains fetching detailed hypervisor info for Xen domains Xen exposes a lot of detail about the hypervisor in /sys/hypervisor. Parse the hypervisor version and the capabilities and expose these as grains. This allows for detailed targeting and appropriate actions, e.g. when running on XenServer install the XenServer guest-tools. Sample output: virtual_hv_features: 000020f0 virtual_hv_features_list: - pae_pgdir_above_4gb - mmu_pt_update_preserve_ad - gnttab_map_avail_bits - memory_op_vnode_supported virtual_hv_version: 4.6.6-2.el7 virtual_hv_version_info: - 4 - 6 - .6-2.el7 --- salt/grains/core.py | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/salt/grains/core.py b/salt/grains/core.py index 5c1ccfdd038b..9bb7b32b8939 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -983,6 +983,59 @@ def _virtual(osdata): ) return grains +def _virtual_hv(osdata): + ''' + Returns detailed hypervisor information from sysfs + Currently this seems to be used only by Xen + ''' + grains = {} + + # Bail early if we're not running on Xen + if 'xen' not in osdata['virtual']: + return grains + + # Try to get the exact hypervisor version from sysfs + try: + version = {} + for file in ('major', 'minor', 'extra'): + with open('/sys/hypervisor/version/%s' % (file,), 'r') as fhr: + version[file] = fhr.read().strip() + grains['virtual_hv_version'] = '%s.%s%s' % (version['major'], version['minor'], version['extra']) + grains['virtual_hv_version_info'] = (version['major'], version['minor'], version['extra']) + except: + pass + + # Try to read and decode the supported feature set of the hypervisor + # Based on https://github.com/brendangregg/Misc/blob/master/xen/xen-features.py + # Table data from include/xen/interface/features.h + xen_feature_table = { 0: 'writable_page_tables', + 1: 'writable_descriptor_tables', + 2: 'auto_translated_physmap', + 3: 'supervisor_mode_kernel', + 4: 'pae_pgdir_above_4gb', + 5: 'mmu_pt_update_preserve_ad', + 7: 'gnttab_map_avail_bits', + 8: 'hvm_callback_vector', + 9: 'hvm_safe_pvclock', + 10: 'hvm_pirqs', + 11: 'dom0', + 12: 'grant_map_identity', + 13: 'memory_op_vnode_supported', + 14: 'ARM_SMCCC_supported' } + try: + with open('/sys/hypervisor/properties/features', 'r') as fhr: + features = fhr.read().strip() + enabled_features = [] + for bit, feat in xen_feature_table.items(): + if int(features, 16) & (1 << bit): + enabled_features.append(feat) + grains['virtual_hv_features'] = features + grains['virtual_hv_features_list'] = enabled_features + except: + pass + + return grains + def _ps(osdata): ''' @@ -1804,6 +1857,7 @@ def os_data(): # Load the virtual machine info grains.update(_virtual(grains)) + grains.update(_virtual_hv(grains)) grains.update(_ps(grains)) if grains.get('osrelease', ''): From 7ca8109cb31431c5c6d6fbc3c0a878db9356e05a Mon Sep 17 00:00:00 2001 From: Andreas Thienemann Date: Wed, 14 Mar 2018 10:18:05 +0100 Subject: [PATCH 2/6] Incorporate lint suggested fixes. --- salt/grains/core.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py index 9bb7b32b8939..3a30d88b4c93 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -975,6 +975,7 @@ def _virtual(osdata): if os.path.isfile('/var/run/xenconsoled.pid'): grains['virtual_subtype'] = 'Xen Dom0' + for command in failed_commands: log.info( "Although '%s' was found in path, the current user " @@ -998,9 +999,9 @@ def _virtual_hv(osdata): try: version = {} for file in ('major', 'minor', 'extra'): - with open('/sys/hypervisor/version/%s' % (file,), 'r') as fhr: + with salt.utils.fopen('/sys/hypervisor/version/{}'.format(file), 'r') as fhr: version[file] = fhr.read().strip() - grains['virtual_hv_version'] = '%s.%s%s' % (version['major'], version['minor'], version['extra']) + grains['virtual_hv_version'] = '{}.{}{}'.format(version['major'], version['minor'], version['extra']) grains['virtual_hv_version_info'] = (version['major'], version['minor'], version['extra']) except: pass @@ -1008,22 +1009,22 @@ def _virtual_hv(osdata): # Try to read and decode the supported feature set of the hypervisor # Based on https://github.com/brendangregg/Misc/blob/master/xen/xen-features.py # Table data from include/xen/interface/features.h - xen_feature_table = { 0: 'writable_page_tables', - 1: 'writable_descriptor_tables', - 2: 'auto_translated_physmap', - 3: 'supervisor_mode_kernel', - 4: 'pae_pgdir_above_4gb', - 5: 'mmu_pt_update_preserve_ad', - 7: 'gnttab_map_avail_bits', - 8: 'hvm_callback_vector', - 9: 'hvm_safe_pvclock', - 10: 'hvm_pirqs', - 11: 'dom0', - 12: 'grant_map_identity', - 13: 'memory_op_vnode_supported', - 14: 'ARM_SMCCC_supported' } + xen_feature_table = {0: 'writable_page_tables', + 1: 'writable_descriptor_tables', + 2: 'auto_translated_physmap', + 3: 'supervisor_mode_kernel', + 4: 'pae_pgdir_above_4gb', + 5: 'mmu_pt_update_preserve_ad', + 7: 'gnttab_map_avail_bits', + 8: 'hvm_callback_vector', + 9: 'hvm_safe_pvclock', + 10: 'hvm_pirqs', + 11: 'dom0', + 12: 'grant_map_identity', + 13: 'memory_op_vnode_supported', + 14: 'ARM_SMCCC_supported'} try: - with open('/sys/hypervisor/properties/features', 'r') as fhr: + with salt.utils.fopen('/sys/hypervisor/properties/features', 'r') as fhr: features = fhr.read().strip() enabled_features = [] for bit, feat in xen_feature_table.items(): From 2d831fc52a7b42321c47662679b36231e9d38245 Mon Sep 17 00:00:00 2001 From: Andreas Thienemann Date: Sat, 17 Mar 2018 13:07:13 +0100 Subject: [PATCH 3/6] Further fixes. --- salt/grains/core.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py index 3a30d88b4c93..355974da4663 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -984,6 +984,7 @@ def _virtual(osdata): ) return grains + def _virtual_hv(osdata): ''' Returns detailed hypervisor information from sysfs @@ -998,9 +999,9 @@ def _virtual_hv(osdata): # Try to get the exact hypervisor version from sysfs try: version = {} - for file in ('major', 'minor', 'extra'): - with salt.utils.fopen('/sys/hypervisor/version/{}'.format(file), 'r') as fhr: - version[file] = fhr.read().strip() + for fn in ('major', 'minor', 'extra'): + with salt.utils.files.fopen('/sys/hypervisor/version/{}'.format(fn), 'r') as fhr: + version[fn] = fhr.read().strip() grains['virtual_hv_version'] = '{}.{}{}'.format(version['major'], version['minor'], version['extra']) grains['virtual_hv_version_info'] = (version['major'], version['minor'], version['extra']) except: @@ -1024,7 +1025,7 @@ def _virtual_hv(osdata): 13: 'memory_op_vnode_supported', 14: 'ARM_SMCCC_supported'} try: - with salt.utils.fopen('/sys/hypervisor/properties/features', 'r') as fhr: + with salt.utils.files.fopen('/sys/hypervisor/properties/features', 'r') as fhr: features = fhr.read().strip() enabled_features = [] for bit, feat in xen_feature_table.items(): From ee6821501f21f93bacf4a9639252096925de9256 Mon Sep 17 00:00:00 2001 From: Andreas Thienemann Date: Sat, 17 Mar 2018 23:07:00 +0100 Subject: [PATCH 4/6] Fix superflous newline. --- salt/grains/core.py | 1 - 1 file changed, 1 deletion(-) diff --git a/salt/grains/core.py b/salt/grains/core.py index 355974da4663..9e2b6eedc279 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -975,7 +975,6 @@ def _virtual(osdata): if os.path.isfile('/var/run/xenconsoled.pid'): grains['virtual_subtype'] = 'Xen Dom0' - for command in failed_commands: log.info( "Although '%s' was found in path, the current user " From fd115c2bd0175fe25229429d21acde4ee4e3ec6c Mon Sep 17 00:00:00 2001 From: Andreas Thienemann Date: Mon, 16 Apr 2018 09:58:30 +0200 Subject: [PATCH 5/6] Incorporate code improvement suggestions from Mike --- salt/grains/core.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py index 9e2b6eedc279..bbdb526cb073 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -54,6 +54,7 @@ import salt.utils.network import salt.utils.path import salt.utils.platform +import salt.utils.stringutils from salt.ext import six from salt.ext.six.moves import range @@ -1000,10 +1001,10 @@ def _virtual_hv(osdata): version = {} for fn in ('major', 'minor', 'extra'): with salt.utils.files.fopen('/sys/hypervisor/version/{}'.format(fn), 'r') as fhr: - version[fn] = fhr.read().strip() + version[fn] = salt.utils.stringutils.to_unicode(fhr.read().strip()) grains['virtual_hv_version'] = '{}.{}{}'.format(version['major'], version['minor'], version['extra']) - grains['virtual_hv_version_info'] = (version['major'], version['minor'], version['extra']) - except: + grains['virtual_hv_version_info'] = [version['major'], version['minor'], version['extra']] + except (IOError, OSError, KeyError): pass # Try to read and decode the supported feature set of the hypervisor @@ -1025,14 +1026,14 @@ def _virtual_hv(osdata): 14: 'ARM_SMCCC_supported'} try: with salt.utils.files.fopen('/sys/hypervisor/properties/features', 'r') as fhr: - features = fhr.read().strip() + features = salt.utils.stringutils.to_unicode(fhr.read().strip()) enabled_features = [] - for bit, feat in xen_feature_table.items(): + for bit, feat in six.iteritems(xen_feature_table): if int(features, 16) & (1 << bit): enabled_features.append(feat) grains['virtual_hv_features'] = features grains['virtual_hv_features_list'] = enabled_features - except: + except (IOError, OSError, KeyError): pass return grains From 095ca4f97a85f7cd6f38cb39f55e7874983e319d Mon Sep 17 00:00:00 2001 From: Andreas Thienemann Date: Wed, 18 Apr 2018 10:01:27 +0200 Subject: [PATCH 6/6] Handle the case the osdata dict doesn't contain any virtual key. This would happen if someone runs on bare metal, an admittedly increasingly rare situation... --- salt/grains/core.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/salt/grains/core.py b/salt/grains/core.py index bbdb526cb073..178fb8ba5372 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -993,7 +993,10 @@ def _virtual_hv(osdata): grains = {} # Bail early if we're not running on Xen - if 'xen' not in osdata['virtual']: + try: + if 'xen' not in osdata['virtual']: + return grains + except KeyError: return grains # Try to get the exact hypervisor version from sysfs