From 56b7483b851fcbd11abcba02c46c8c11845f1db7 Mon Sep 17 00:00:00 2001 From: Adrian Likins Date: Tue, 13 Jun 2017 15:31:41 -0400 Subject: [PATCH] More statvfs info for mount facts rebase 12073 (#25454) * Add more mount point statvfs info including sizes Based on https://github.com/ansible/ansible/pull/12073 facts.utils.get_mount_size() now returns a dict of most of the posix statvfs data, including block_size and inode counts. Update the facts.hardware classes that use get_mount_size() to use the new info by mount_info.update(mount_statvfs_inof) to merge. * add back unit tests for LinuxHardware mount/fs facts * add test cases for facts.utils.get_mount_size --- .../module_utils/facts/hardware/freebsd.py | 16 +- .../module_utils/facts/hardware/linux.py | 7 +- .../module_utils/facts/hardware/netbsd.py | 16 +- .../module_utils/facts/hardware/openbsd.py | 16 +- .../module_utils/facts/hardware/sunos.py | 18 +- lib/ansible/module_utils/facts/utils.py | 21 +- .../module_utils/facts/hardware/__init__.py | 0 .../module_utils/facts/hardware/linux_data.py | 340 ++++++++++++++++++ .../module_utils/facts/hardware/test_linux.py | 164 +++++++++ test/units/module_utils/facts/test_utils.py | 39 ++ 10 files changed, 591 insertions(+), 46 deletions(-) create mode 100644 test/units/module_utils/facts/hardware/__init__.py create mode 100644 test/units/module_utils/facts/hardware/linux_data.py create mode 100644 test/units/module_utils/facts/hardware/test_linux.py create mode 100644 test/units/module_utils/facts/test_utils.py diff --git a/lib/ansible/module_utils/facts/hardware/freebsd.py b/lib/ansible/module_utils/facts/hardware/freebsd.py index 609a13f339a..ee894b01e0f 100644 --- a/lib/ansible/module_utils/facts/hardware/freebsd.py +++ b/lib/ansible/module_utils/facts/hardware/freebsd.py @@ -121,15 +121,13 @@ class FreeBSDHardware(Hardware): if line.startswith('#') or line.strip() == '': continue fields = re.sub(r'\s+', ' ', line).split() - size_total, size_available = get_mount_size(fields[1]) - mount_facts['mounts'].append({ - 'mount': fields[1], - 'device': fields[0], - 'fstype': fields[2], - 'options': fields[3], - 'size_total': size_total, - 'size_available': size_available - }) + mount_statvfs_info = get_mount_size(fields[1]) + mount_info = {'mount': fields[1], + 'device': fields[0], + 'fstype': fields[2], + 'options': fields[3]} + mount_info.update(mount_statvfs_info) + mount_facts['mounts'].append(mount_info) return mount_facts diff --git a/lib/ansible/module_utils/facts/hardware/linux.py b/lib/ansible/module_utils/facts/hardware/linux.py index 33851e199c6..042c3d6330b 100644 --- a/lib/ansible/module_utils/facts/hardware/linux.py +++ b/lib/ansible/module_utils/facts/hardware/linux.py @@ -428,7 +428,7 @@ class LinuxHardware(Hardware): if fstype == 'none': continue - size_total, size_available = get_mount_size(mount) + mount_statvfs_info = get_mount_size(mount) if mount in bind_mounts: # only add if not already there, we might have a plain /etc/mtab @@ -439,11 +439,10 @@ class LinuxHardware(Hardware): 'device': device, 'fstype': fstype, 'options': options, - # statvfs data - 'size_total': size_total, - 'size_available': size_available, 'uuid': uuids.get(device, 'N/A')} + mount_info.update(mount_statvfs_info) + mounts.append(mount_info) mount_facts['mounts'] = mounts diff --git a/lib/ansible/module_utils/facts/hardware/netbsd.py b/lib/ansible/module_utils/facts/hardware/netbsd.py index c716ea454c8..84b544cef0f 100644 --- a/lib/ansible/module_utils/facts/hardware/netbsd.py +++ b/lib/ansible/module_utils/facts/hardware/netbsd.py @@ -125,15 +125,13 @@ class NetBSDHardware(Hardware): if line.startswith('#') or line.strip() == '': continue fields = re.sub(r'\s+', ' ', line).split() - size_total, size_available = get_mount_size(fields[1]) - mount_facts['mounts'].append({ - 'mount': fields[1], - 'device': fields[0], - 'fstype': fields[2], - 'options': fields[3], - 'size_total': size_total, - 'size_available': size_available - }) + mount_statvfs_info = get_mount_size(fields[1]) + mount_info = {'mount': fields[1], + 'device': fields[0], + 'fstype': fields[2], + 'options': fields[3]} + mount_info.update(mount_statvfs_info) + mount_facts['mounts'].append(mount_info) return mount_facts def get_dmi_facts(self): diff --git a/lib/ansible/module_utils/facts/hardware/openbsd.py b/lib/ansible/module_utils/facts/hardware/openbsd.py index d66ce21268f..6b666047373 100644 --- a/lib/ansible/module_utils/facts/hardware/openbsd.py +++ b/lib/ansible/module_utils/facts/hardware/openbsd.py @@ -80,15 +80,13 @@ class OpenBSDHardware(Hardware): fields = re.sub(r'\s+', ' ', line).split() if fields[1] == 'none' or fields[3] == 'xx': continue - size_total, size_available = get_mount_size(fields[1]) - mount_facts['mounts'].append({ - 'mount': fields[1], - 'device': fields[0], - 'fstype': fields[2], - 'options': fields[3], - 'size_total': size_total, - 'size_available': size_available - }) + mount_statvfs_info = get_mount_size(fields[1]) + mount_info = {'mount': fields[1], + 'device': fields[0], + 'fstype': fields[2], + 'options': fields[3]} + mount_info.update(mount_statvfs_info) + mount_facts['mounts'].append(mount_info) return mount_facts def get_memory_facts(self): diff --git a/lib/ansible/module_utils/facts/hardware/sunos.py b/lib/ansible/module_utils/facts/hardware/sunos.py index 595e100a88a..5e62dc2fc35 100644 --- a/lib/ansible/module_utils/facts/hardware/sunos.py +++ b/lib/ansible/module_utils/facts/hardware/sunos.py @@ -154,16 +154,14 @@ class SunOSHardware(Hardware): if fstab: for line in fstab.splitlines(): fields = line.split('\t') - size_total, size_available = get_mount_size(fields[1]) - mount_facts['mounts'].append({ - 'mount': fields[1], - 'device': fields[0], - 'fstype': fields[2], - 'options': fields[3], - 'time': fields[4], - 'size_total': size_total, - 'size_available': size_available - }) + mount_statvfs_info = get_mount_size(fields[1]) + mount_info = {'mount': fields[1], + 'device': fields[0], + 'fstype': fields[2], + 'options': fields[3], + 'time': fields[4]} + mount_info.update(mount_statvfs_info) + mount_facts['mounts'].append(mount_info) return mount_facts diff --git a/lib/ansible/module_utils/facts/utils.py b/lib/ansible/module_utils/facts/utils.py index 7b2f6157d03..2446ae678c2 100644 --- a/lib/ansible/module_utils/facts/utils.py +++ b/lib/ansible/module_utils/facts/utils.py @@ -47,13 +47,24 @@ def get_file_lines(path): def get_mount_size(mountpoint): - size_total = None - size_available = None + mount_size = {} + try: statvfs_result = os.statvfs(mountpoint) - size_total = statvfs_result.f_frsize * statvfs_result.f_blocks - size_available = statvfs_result.f_frsize * (statvfs_result.f_bavail) + mount_size['size_total'] = statvfs_result.f_frsize * statvfs_result.f_blocks + mount_size['size_available'] = statvfs_result.f_frsize * (statvfs_result.f_bavail) + + # Block total/available/used + mount_size['block_size'] = statvfs_result.f_bsize + mount_size['block_total'] = statvfs_result.f_blocks + mount_size['block_available'] = statvfs_result.f_bavail + mount_size['block_used'] = mount_size['block_total'] - mount_size['block_available'] + + # Inode total/available/used + mount_size['inode_total'] = statvfs_result.f_files + mount_size['inode_available'] = statvfs_result.f_favail + mount_size['inode_used'] = mount_size['inode_total'] - mount_size['inode_available'] except OSError: pass - return size_total, size_available + return mount_size diff --git a/test/units/module_utils/facts/hardware/__init__.py b/test/units/module_utils/facts/hardware/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/units/module_utils/facts/hardware/linux_data.py b/test/units/module_utils/facts/hardware/linux_data.py new file mode 100644 index 00000000000..61f0d0a5113 --- /dev/null +++ b/test/units/module_utils/facts/hardware/linux_data.py @@ -0,0 +1,340 @@ +# This file is part of Ansible +# +# Ansible 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. +# +# Ansible 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 Ansible. If not, see . + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +LSBLK_OUTPUT = b""" +/dev/sda +/dev/sda1 32caaec3-ef40-4691-a3b6-438c3f9bc1c0 +/dev/sda2 66Ojcd-ULtu-1cZa-Tywo-mx0d-RF4O-ysA9jK +/dev/mapper/fedora_dhcp129--186-swap eae6059d-2fbe-4d1c-920d-a80bbeb1ac6d +/dev/mapper/fedora_dhcp129--186-root d34cf5e3-3449-4a6c-8179-a1feb2bca6ce +/dev/mapper/fedora_dhcp129--186-home 2d3e4853-fa69-4ccf-8a6a-77b05ab0a42d +/dev/sr0 +/dev/loop0 0f031512-ab15-497d-9abd-3a512b4a9390 +/dev/loop1 7c1b0f30-cf34-459f-9a70-2612f82b870a +/dev/loop9 0f031512-ab15-497d-9abd-3a512b4a9390 +/dev/loop9 7c1b4444-cf34-459f-9a70-2612f82b870a +/dev/mapper/docker-253:1-1050967-pool +/dev/loop2 +/dev/mapper/docker-253:1-1050967-pool +""" + +LSBLK_OUTPUT_2 = b""" +/dev/sda +/dev/sda1 32caaec3-ef40-4691-a3b6-438c3f9bc1c0 +/dev/sda2 66Ojcd-ULtu-1cZa-Tywo-mx0d-RF4O-ysA9jK +/dev/mapper/fedora_dhcp129--186-swap eae6059d-2fbe-4d1c-920d-a80bbeb1ac6d +/dev/mapper/fedora_dhcp129--186-root d34cf5e3-3449-4a6c-8179-a1feb2bca6ce +/dev/mapper/fedora_dhcp129--186-home 2d3e4853-fa69-4ccf-8a6a-77b05ab0a42d +/dev/mapper/an-example-mapper with a space in the name 84639acb-013f-4d2f-9392-526a572b4373 +/dev/sr0 +/dev/loop0 0f031512-ab15-497d-9abd-3a512b4a9390 +""" + +LSBLK_UUIDS = {'/dev/sda1': '66Ojcd-ULtu-1cZa-Tywo-mx0d-RF4O-ysA9jK'} + +MTAB = """ +sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0 +proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0 +devtmpfs /dev devtmpfs rw,seclabel,nosuid,size=8044400k,nr_inodes=2011100,mode=755 0 0 +securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0 +tmpfs /dev/shm tmpfs rw,seclabel,nosuid,nodev 0 0 +devpts /dev/pts devpts rw,seclabel,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0 +tmpfs /run tmpfs rw,seclabel,nosuid,nodev,mode=755 0 0 +tmpfs /sys/fs/cgroup tmpfs ro,seclabel,nosuid,nodev,noexec,mode=755 0 0 +cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd 0 0 +pstore /sys/fs/pstore pstore rw,seclabel,nosuid,nodev,noexec,relatime 0 0 +cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0 +cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0 +cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0 +cgroup /sys/fs/cgroup/pids cgroup rw,nosuid,nodev,noexec,relatime,pids 0 0 +cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0 +cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0 +cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0 +cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0 +cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0 +cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_cls,net_prio 0 0 +configfs /sys/kernel/config configfs rw,relatime 0 0 +/dev/mapper/fedora_dhcp129--186-root / ext4 rw,seclabel,relatime,data=ordered 0 0 +selinuxfs /sys/fs/selinux selinuxfs rw,relatime 0 0 +systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime,fd=24,pgrp=1,timeout=0,minproto=5,maxproto=5,direct 0 0 +debugfs /sys/kernel/debug debugfs rw,seclabel,relatime 0 0 +hugetlbfs /dev/hugepages hugetlbfs rw,seclabel,relatime 0 0 +tmpfs /tmp tmpfs rw,seclabel 0 0 +mqueue /dev/mqueue mqueue rw,seclabel,relatime 0 0 +/dev/loop0 /var/lib/machines btrfs rw,seclabel,relatime,space_cache,subvolid=5,subvol=/ 0 0 +/dev/sda1 /boot ext4 rw,seclabel,relatime,data=ordered 0 0 +/dev/mapper/fedora_dhcp129--186-home /home ext4 rw,seclabel,relatime,data=ordered 0 0 +tmpfs /run/user/1000 tmpfs rw,seclabel,nosuid,nodev,relatime,size=1611044k,mode=700,uid=1000,gid=1000 0 0 +gvfsd-fuse /run/user/1000/gvfs fuse.gvfsd-fuse rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0 +fusectl /sys/fs/fuse/connections fusectl rw,relatime 0 0 +grimlock.g.a: /home/adrian/sshfs-grimlock fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0 +grimlock.g.a:test_path/path_with'single_quotes /home/adrian/sshfs-grimlock-single-quote fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0 +grimlock.g.a:path_with'single_quotes /home/adrian/sshfs-grimlock-single-quote-2 fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0 +grimlock.g.a:/mnt/data/foto's /home/adrian/fotos fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0 +""" + +MTAB_ENTRIES = [ + [ + 'sysfs', + '/sys', + 'sysfs', + 'rw,seclabel,nosuid,nodev,noexec,relatime', + '0', + '0' + ], + ['proc', '/proc', 'proc', 'rw,nosuid,nodev,noexec,relatime', '0', '0'], + [ + 'devtmpfs', + '/dev', + 'devtmpfs', + 'rw,seclabel,nosuid,size=8044400k,nr_inodes=2011100,mode=755', + '0', + '0' + ], + [ + 'securityfs', + '/sys/kernel/security', + 'securityfs', + 'rw,nosuid,nodev,noexec,relatime', + '0', + '0' + ], + ['tmpfs', '/dev/shm', 'tmpfs', 'rw,seclabel,nosuid,nodev', '0', '0'], + [ + 'devpts', + '/dev/pts', + 'devpts', + 'rw,seclabel,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000', + '0', + '0' + ], + ['tmpfs', '/run', 'tmpfs', 'rw,seclabel,nosuid,nodev,mode=755', '0', '0'], + [ + 'tmpfs', + '/sys/fs/cgroup', + 'tmpfs', + 'ro,seclabel,nosuid,nodev,noexec,mode=755', + '0', + '0' + ], + [ + 'cgroup', + '/sys/fs/cgroup/systemd', + 'cgroup', + 'rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd', + '0', + '0' + ], + [ + 'pstore', + '/sys/fs/pstore', + 'pstore', + 'rw,seclabel,nosuid,nodev,noexec,relatime', + '0', + '0' + ], + [ + 'cgroup', + '/sys/fs/cgroup/devices', + 'cgroup', + 'rw,nosuid,nodev,noexec,relatime,devices', + '0', + '0' + ], + [ + 'cgroup', + '/sys/fs/cgroup/freezer', + 'cgroup', + 'rw,nosuid,nodev,noexec,relatime,freezer', + '0', + '0' + ], + [ + 'cgroup', + '/sys/fs/cgroup/memory', + 'cgroup', + 'rw,nosuid,nodev,noexec,relatime,memory', + '0', + '0' + ], + [ + 'cgroup', + '/sys/fs/cgroup/pids', + 'cgroup', + 'rw,nosuid,nodev,noexec,relatime,pids', + '0', + '0' + ], + [ + 'cgroup', + '/sys/fs/cgroup/blkio', + 'cgroup', + 'rw,nosuid,nodev,noexec,relatime,blkio', + '0', + '0' + ], + [ + 'cgroup', + '/sys/fs/cgroup/cpuset', + 'cgroup', + 'rw,nosuid,nodev,noexec,relatime,cpuset', + '0', + '0' + ], + [ + 'cgroup', + '/sys/fs/cgroup/cpu,cpuacct', + 'cgroup', + 'rw,nosuid,nodev,noexec,relatime,cpu,cpuacct', + '0', + '0' + ], + [ + 'cgroup', + '/sys/fs/cgroup/hugetlb', + 'cgroup', + 'rw,nosuid,nodev,noexec,relatime,hugetlb', + '0', + '0' + ], + [ + 'cgroup', + '/sys/fs/cgroup/perf_event', + 'cgroup', + 'rw,nosuid,nodev,noexec,relatime,perf_event', + '0', + '0' + ], + [ + 'cgroup', + '/sys/fs/cgroup/net_cls,net_prio', + 'cgroup', + 'rw,nosuid,nodev,noexec,relatime,net_cls,net_prio', + '0', + '0' + ], + ['configfs', '/sys/kernel/config', 'configfs', 'rw,relatime', '0', '0'], + [ + '/dev/mapper/fedora_dhcp129--186-root', + '/', + 'ext4', + 'rw,seclabel,relatime,data=ordered', + '0', + '0' + ], + ['selinuxfs', '/sys/fs/selinux', 'selinuxfs', 'rw,relatime', '0', '0'], + [ + 'systemd-1', + '/proc/sys/fs/binfmt_misc', + 'autofs', + 'rw,relatime,fd=24,pgrp=1,timeout=0,minproto=5,maxproto=5,direct', + '0', + '0' + ], + ['debugfs', '/sys/kernel/debug', 'debugfs', 'rw,seclabel,relatime', '0', '0'], + [ + 'hugetlbfs', + '/dev/hugepages', + 'hugetlbfs', + 'rw,seclabel,relatime', + '0', + '0' + ], + ['tmpfs', '/tmp', 'tmpfs', 'rw,seclabel', '0', '0'], + ['mqueue', '/dev/mqueue', 'mqueue', 'rw,seclabel,relatime', '0', '0'], + [ + '/dev/loop0', + '/var/lib/machines', + 'btrfs', + 'rw,seclabel,relatime,space_cache,subvolid=5,subvol=/', + '0', + '0' + ], + ['/dev/sda1', '/boot', 'ext4', 'rw,seclabel,relatime,data=ordered', '0', '0'], + # A 'none' fstype + ['/dev/sdz3', '/not/a/real/device', 'none', 'rw,seclabel,relatime,data=ordered', '0', '0'], + # lets assume this is a bindmount + ['/dev/sdz4', '/not/a/real/bind_mount', 'ext4', 'rw,seclabel,relatime,data=ordered', '0', '0'], + [ + '/dev/mapper/fedora_dhcp129--186-home', + '/home', + 'ext4', + 'rw,seclabel,relatime,data=ordered', + '0', + '0' + ], + [ + 'tmpfs', + '/run/user/1000', + 'tmpfs', + 'rw,seclabel,nosuid,nodev,relatime,size=1611044k,mode=700,uid=1000,gid=1000', + '0', + '0' + ], + [ + 'gvfsd-fuse', + '/run/user/1000/gvfs', + 'fuse.gvfsd-fuse', + 'rw,nosuid,nodev,relatime,user_id=1000,group_id=1000', + '0', + '0' + ], + ['fusectl', '/sys/fs/fuse/connections', 'fusectl', 'rw,relatime', '0', '0']] + +STATVFS_INFO = {'/': {'block_available': 10192323, + 'block_size': 4096, + 'block_total': 12868728, + 'block_used': 2676405, + 'inode_available': 3061699, + 'inode_total': 3276800, + 'inode_used': 215101, + 'size_available': 41747755008, + 'size_total': 52710309888}, + '/not/a/real/bind_mount': {}, + '/home': {'block_available': 1001578731, + 'block_size': 4096, + 'block_total': 105871006, + 'block_used': 5713133, + 'inode_available': 26860880, + 'inode_total': 26902528, + 'inode_used': 41648, + 'size_available': 410246647808, + 'size_total': 433647640576}, + '/var/lib/machines': {'block_available': 10192316, + 'block_size': 4096, + 'block_total': 12868728, + 'block_used': 2676412, + 'inode_available': 3061699, + 'inode_total': 3276800, + 'inode_used': 215101, + 'size_available': 41747726336, + 'size_total': 52710309888}, + '/boot': {'block_available': 187585, + 'block_size': 4096, + 'block_total': 249830, + 'block_used': 62245, + 'inode_available': 65096, + 'inode_total': 65536, + 'inode_used': 440, + 'size_available': 768348160, + 'size_total': 1023303680} + } + +# ['/dev/sdz4', '/not/a/real/bind_mount', 'ext4', 'rw,seclabel,relatime,data=ordered', '0', '0'], + +BIND_MOUNTS = ['/not/a/real/bind_mount'] diff --git a/test/units/module_utils/facts/hardware/test_linux.py b/test/units/module_utils/facts/hardware/test_linux.py new file mode 100644 index 00000000000..b5dd81892c9 --- /dev/null +++ b/test/units/module_utils/facts/hardware/test_linux.py @@ -0,0 +1,164 @@ +# This file is part of Ansible +# +# Ansible 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. +# +# Ansible 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 Ansible. If not, see . + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os + +from ansible.compat.tests import unittest +from ansible.compat.tests.mock import Mock, patch + +from ansible.module_utils.facts import timeout + +from ansible.module_utils.facts.hardware import linux + +from . linux_data import LSBLK_OUTPUT, LSBLK_OUTPUT_2, LSBLK_UUIDS, MTAB, MTAB_ENTRIES, BIND_MOUNTS, STATVFS_INFO + +with open(os.path.join(os.path.dirname(__file__), '../fixtures/findmount_output.txt')) as f: + FINDMNT_OUTPUT = f.read() + +GET_MOUNT_SIZE = {} + + +def mock_get_mount_size(mountpoint): + return STATVFS_INFO.get(mountpoint, {}) + + +class TestFactsLinuxHardwareGetMountFacts(unittest.TestCase): + + # FIXME: mock.patch instead + def setUp(self): + timeout.GATHER_TIMEOUT = 10 + + def tearDown(self): + timeout.GATHER_TIMEOUT = None + + @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._mtab_entries', return_value=MTAB_ENTRIES) + @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._find_bind_mounts', return_value=BIND_MOUNTS) + @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._lsblk_uuid', return_value=LSBLK_UUIDS) + @patch('ansible.module_utils.facts.hardware.linux.get_mount_size', side_effect=mock_get_mount_size) + def test_get_mount_facts(self, + mock_get_mount_size, + mock_lsblk_uuid, + mock_find_bind_mounts, + mock_mtab_entries): + module = Mock() + # Returns a LinuxHardware-ish + lh = linux.LinuxHardware(module=module, load_on_init=False) + + # Nothing returned, just self.facts modified as a side effect + mount_facts = lh.get_mount_facts() + self.assertIsInstance(mount_facts, dict) + self.assertIn('mounts', mount_facts) + self.assertIsInstance(mount_facts['mounts'], list) + self.assertIsInstance(mount_facts['mounts'][0], dict) + + home_expected = {'block_available': 1001578731, + 'block_size': 4096, + 'block_total': 105871006, + 'block_used': 5713133, + 'device': '/dev/mapper/fedora_dhcp129--186-home', + 'fstype': 'ext4', + 'inode_available': 26860880, + 'inode_total': 26902528, + 'inode_used': 41648, + 'mount': '/home', + 'options': 'rw,seclabel,relatime,data=ordered', + 'size_available': 410246647808, + 'size_total': 433647640576, + 'uuid': 'N/A'} + home_info = [x for x in mount_facts['mounts'] if x['mount'] == '/home'][0] + + self.assertDictEqual(home_info, home_expected) + + @patch('ansible.module_utils.facts.hardware.linux.get_file_content', return_value=MTAB) + def test_get_mtab_entries(self, mock_get_file_content): + + module = Mock() + lh = linux.LinuxHardware(module=module, load_on_init=False) + mtab_entries = lh._mtab_entries() + self.assertIsInstance(mtab_entries, list) + self.assertIsInstance(mtab_entries[0], list) + self.assertEqual(len(mtab_entries), 38) + + @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._run_findmnt', return_value=(0, FINDMNT_OUTPUT, '')) + def test_find_bind_mounts(self, mock_run_findmnt): + module = Mock() + lh = linux.LinuxHardware(module=module, load_on_init=False) + bind_mounts = lh._find_bind_mounts() + + # If bind_mounts becomes another seq type, feel free to change + self.assertIsInstance(bind_mounts, set) + self.assertEqual(len(bind_mounts), 1) + self.assertIn('/not/a/real/bind_mount', bind_mounts) + + @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._run_findmnt', return_value=(37, '', '')) + def test_find_bind_mounts_non_zero(self, mock_run_findmnt): + module = Mock() + lh = linux.LinuxHardware(module=module, load_on_init=False) + bind_mounts = lh._find_bind_mounts() + + self.assertIsInstance(bind_mounts, set) + self.assertEqual(len(bind_mounts), 0) + + def test_find_bind_mounts_no_findmnts(self): + module = Mock() + module.get_bin_path = Mock(return_value=None) + lh = linux.LinuxHardware(module=module, load_on_init=False) + bind_mounts = lh._find_bind_mounts() + + self.assertIsInstance(bind_mounts, set) + self.assertEqual(len(bind_mounts), 0) + + @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._run_lsblk', return_value=(0, LSBLK_OUTPUT, '')) + def test_lsblk_uuid(self, mock_run_lsblk): + module = Mock() + lh = linux.LinuxHardware(module=module, load_on_init=False) + lsblk_uuids = lh._lsblk_uuid() + + self.assertIsInstance(lsblk_uuids, dict) + self.assertIn(b'/dev/loop9', lsblk_uuids) + self.assertIn(b'/dev/sda1', lsblk_uuids) + self.assertEqual(lsblk_uuids[b'/dev/sda1'], b'32caaec3-ef40-4691-a3b6-438c3f9bc1c0') + + @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._run_lsblk', return_value=(37, LSBLK_OUTPUT, '')) + def test_lsblk_uuid_non_zero(self, mock_run_lsblk): + module = Mock() + lh = linux.LinuxHardware(module=module, load_on_init=False) + lsblk_uuids = lh._lsblk_uuid() + + self.assertIsInstance(lsblk_uuids, dict) + self.assertEqual(len(lsblk_uuids), 0) + + def test_lsblk_uuid_no_lsblk(self): + module = Mock() + module.get_bin_path = Mock(return_value=None) + lh = linux.LinuxHardware(module=module, load_on_init=False) + lsblk_uuids = lh._lsblk_uuid() + + self.assertIsInstance(lsblk_uuids, dict) + self.assertEqual(len(lsblk_uuids), 0) + + @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._run_lsblk', return_value=(0, LSBLK_OUTPUT_2, '')) + def test_lsblk_uuid_dev_with_space_in_name(self, mock_run_lsblk): + module = Mock() + lh = linux.LinuxHardware(module=module, load_on_init=False) + lsblk_uuids = lh._lsblk_uuid() + self.assertIsInstance(lsblk_uuids, dict) + self.assertIn(b'/dev/loop0', lsblk_uuids) + self.assertIn(b'/dev/sda1', lsblk_uuids) + self.assertEqual(lsblk_uuids[b'/dev/mapper/an-example-mapper with a space in the name'], b'84639acb-013f-4d2f-9392-526a572b4373') + self.assertEqual(lsblk_uuids[b'/dev/sda1'], b'32caaec3-ef40-4691-a3b6-438c3f9bc1c0') diff --git a/test/units/module_utils/facts/test_utils.py b/test/units/module_utils/facts/test_utils.py new file mode 100644 index 00000000000..b35f68d2fc9 --- /dev/null +++ b/test/units/module_utils/facts/test_utils.py @@ -0,0 +1,39 @@ +# This file is part of Ansible +# +# Ansible 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. +# +# Ansible 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 Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division) +__metaclass__ = type + +from ansible.compat.tests import unittest +from ansible.compat.tests.mock import patch + +from ansible.module_utils.facts import utils + + +class TestGetMountSize(unittest.TestCase): + def test(self): + mount_info = utils.get_mount_size('/dev/null/not/a/real/mountpoint') + self.assertIsInstance(mount_info, dict) + + def test_proc(self): + mount_info = utils.get_mount_size('/proc') + self.assertIsInstance(mount_info, dict) + + @patch('ansible.module_utils.facts.utils.os.statvfs', side_effect=OSError('intentionally induced os error')) + def test_oserror_on_statvfs(self, mock_statvfs): + mount_info = utils.get_mount_size('/dev/null/doesnt/matter') + self.assertIsInstance(mount_info, dict) + self.assertDictEqual(mount_info, {})