From d46dd99f47c0ee5081d15bc5b741e9096d8bfd3e Mon Sep 17 00:00:00 2001 From: Adrian Likins Date: Tue, 13 Jun 2017 15:33:13 -0400 Subject: [PATCH] Add UUID, label and id links to devices when building facts (#25448) At present, the available facts around block devices are not sufficient to be able to find stable names guaranteed to work across reboots, or to identify block devices by label (UUID, etc). This patch provides a list of observed links for each device. It relies on functionality specific to Linux (as does the existing sysfs-based code which it extends), but should not cause issues on other platforms. Moreover, it prevents virtual devices from being excluded, and links such devices to the physical devices to which they are attached. --- .../module_utils/facts/hardware/linux.py | 55 +++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/lib/ansible/module_utils/facts/hardware/linux.py b/lib/ansible/module_utils/facts/hardware/linux.py index 042c3d6330..6e267536c6 100644 --- a/lib/ansible/module_utils/facts/hardware/linux.py +++ b/lib/ansible/module_utils/facts/hardware/linux.py @@ -16,12 +16,16 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type +import collections import errno +import glob import json import os import re import sys +from ansible.module_utils.six import iteritems + from ansible.module_utils.basic import bytes_to_human from ansible.module_utils.facts.hardware.base import Hardware, HardwareCollector @@ -449,6 +453,41 @@ class LinuxHardware(Hardware): return mount_facts + def get_device_links(self, link_dir): + if not os.path.exists(link_dir): + return {} + try: + retval = collections.defaultdict(set) + for entry in os.listdir(link_dir): + try: + target = os.path.basename(os.readlink(os.path.join(link_dir, entry))) + retval[target].add(entry) + except OSError: + continue + return dict((k, list(sorted(v))) for (k, v) in iteritems(retval)) + except OSError: + return {} + + def get_all_device_owners(self): + try: + retval = collections.defaultdict(set) + for path in glob.glob('/sys/block/*/slaves/*'): + elements = path.split('/') + device = elements[3] + target = elements[5] + retval[target].add(device) + return dict((k, list(sorted(v))) for (k, v) in iteritems(retval)) + except OSError: + return {} + + def get_all_device_links(self): + return { + 'ids': self.get_device_links('/dev/disk/by-id'), + 'uuids': self.get_device_links('/dev/disk/by-uuid'), + 'labels': self.get_device_links('/dev/disk/by-label'), + 'masters': self.get_all_device_owners(), + } + def get_holders(self, block_dev_dict, sysdir): block_dev_dict['holders'] = [] if os.path.isdir(sysdir + "/holders"): @@ -490,6 +529,9 @@ class LinuxHardware(Hardware): continue devs_wwn[os.path.basename(wwn_link)] = link_name[4:] + links = self.get_all_device_links() + device_facts['device_links'] = links + for block in block_devs: virtual = 1 sysfs_no_links = 0 @@ -502,17 +544,17 @@ class LinuxHardware(Hardware): sysfs_no_links = 1 else: continue - if "virtual" in path: - continue sysdir = os.path.join("/sys/block", path) if sysfs_no_links == 1: for folder in os.listdir(sysdir): if "device" in folder: virtual = 0 break - if virtual: - continue d = {} + d['virtual'] = virtual + d['links'] = {} + for (link_type, link_values) in iteritems(links): + d['links'][link_type] = link_values.get(block, []) diskname = os.path.basename(sysdir) for key in ['vendor', 'model', 'sas_address', 'sas_device_handle']: d[key] = get_file_content(sysdir + "/device/" + key) @@ -546,8 +588,13 @@ class LinuxHardware(Hardware): partname = m.group(1) part_sysdir = sysdir + "/" + partname + part['links'] = {} + for (link_type, link_values) in iteritems(links): + part['links'][link_type] = link_values.get(partname, []) + part['start'] = get_file_content(part_sysdir + "/start", 0) part['sectors'] = get_file_content(part_sysdir + "/size", 0) + part['sectorsize'] = get_file_content(part_sysdir + "/queue/logical_block_size") if not part['sectorsize']: part['sectorsize'] = get_file_content(part_sysdir + "/queue/hw_sector_size", 512)