1# This file is part of Ansible
2#
3# Ansible is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation, either version 3 of the License, or
6# (at your option) any later version.
7#
8# Ansible is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
15
16from __future__ import (absolute_import, division, print_function)
17__metaclass__ = type
18
19import os
20
21from units.compat import unittest
22from units.compat.mock import Mock, patch
23
24from ansible.module_utils.facts import timeout
25
26from ansible.module_utils.facts.hardware import linux
27
28from . linux_data import LSBLK_OUTPUT, LSBLK_OUTPUT_2, LSBLK_UUIDS, MTAB, MTAB_ENTRIES, BIND_MOUNTS, STATVFS_INFO, UDEVADM_UUID, UDEVADM_OUTPUT
29
30with open(os.path.join(os.path.dirname(__file__), '../fixtures/findmount_output.txt')) as f:
31    FINDMNT_OUTPUT = f.read()
32
33GET_MOUNT_SIZE = {}
34
35
36def mock_get_mount_size(mountpoint):
37    return STATVFS_INFO.get(mountpoint, {})
38
39
40class TestFactsLinuxHardwareGetMountFacts(unittest.TestCase):
41
42    # FIXME: mock.patch instead
43    def setUp(self):
44        timeout.GATHER_TIMEOUT = 10
45
46    def tearDown(self):
47        timeout.GATHER_TIMEOUT = None
48
49    @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._mtab_entries', return_value=MTAB_ENTRIES)
50    @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._find_bind_mounts', return_value=BIND_MOUNTS)
51    @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._lsblk_uuid', return_value=LSBLK_UUIDS)
52    @patch('ansible.module_utils.facts.hardware.linux.get_mount_size', side_effect=mock_get_mount_size)
53    @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._udevadm_uuid', return_value=UDEVADM_UUID)
54    def test_get_mount_facts(self,
55                             mock_get_mount_size,
56                             mock_lsblk_uuid,
57                             mock_find_bind_mounts,
58                             mock_mtab_entries,
59                             mock_udevadm_uuid):
60        module = Mock()
61        # Returns a LinuxHardware-ish
62        lh = linux.LinuxHardware(module=module, load_on_init=False)
63
64        # Nothing returned, just self.facts modified as a side effect
65        mount_facts = lh.get_mount_facts()
66        self.assertIsInstance(mount_facts, dict)
67        self.assertIn('mounts', mount_facts)
68        self.assertIsInstance(mount_facts['mounts'], list)
69        self.assertIsInstance(mount_facts['mounts'][0], dict)
70
71        home_expected = {'block_available': 1001578731,
72                         'block_size': 4096,
73                         'block_total': 105871006,
74                         'block_used': 5713133,
75                         'device': '/dev/mapper/fedora_dhcp129--186-home',
76                         'fstype': 'ext4',
77                         'inode_available': 26860880,
78                         'inode_total': 26902528,
79                         'inode_used': 41648,
80                         'mount': '/home',
81                         'options': 'rw,seclabel,relatime,data=ordered',
82                         'size_available': 410246647808,
83                         'size_total': 433647640576,
84                         'uuid': 'N/A'}
85        home_info = [x for x in mount_facts['mounts'] if x['mount'] == '/home'][0]
86
87        self.maxDiff = 4096
88        self.assertDictEqual(home_info, home_expected)
89
90    @patch('ansible.module_utils.facts.hardware.linux.get_file_content', return_value=MTAB)
91    def test_get_mtab_entries(self, mock_get_file_content):
92
93        module = Mock()
94        lh = linux.LinuxHardware(module=module, load_on_init=False)
95        mtab_entries = lh._mtab_entries()
96        self.assertIsInstance(mtab_entries, list)
97        self.assertIsInstance(mtab_entries[0], list)
98        self.assertEqual(len(mtab_entries), 38)
99
100    @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._run_findmnt', return_value=(0, FINDMNT_OUTPUT, ''))
101    def test_find_bind_mounts(self, mock_run_findmnt):
102        module = Mock()
103        lh = linux.LinuxHardware(module=module, load_on_init=False)
104        bind_mounts = lh._find_bind_mounts()
105
106        # If bind_mounts becomes another seq type, feel free to change
107        self.assertIsInstance(bind_mounts, set)
108        self.assertEqual(len(bind_mounts), 1)
109        self.assertIn('/not/a/real/bind_mount', bind_mounts)
110
111    @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._run_findmnt', return_value=(37, '', ''))
112    def test_find_bind_mounts_non_zero(self, mock_run_findmnt):
113        module = Mock()
114        lh = linux.LinuxHardware(module=module, load_on_init=False)
115        bind_mounts = lh._find_bind_mounts()
116
117        self.assertIsInstance(bind_mounts, set)
118        self.assertEqual(len(bind_mounts), 0)
119
120    def test_find_bind_mounts_no_findmnts(self):
121        module = Mock()
122        module.get_bin_path = Mock(return_value=None)
123        lh = linux.LinuxHardware(module=module, load_on_init=False)
124        bind_mounts = lh._find_bind_mounts()
125
126        self.assertIsInstance(bind_mounts, set)
127        self.assertEqual(len(bind_mounts), 0)
128
129    @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._run_lsblk', return_value=(0, LSBLK_OUTPUT, ''))
130    def test_lsblk_uuid(self, mock_run_lsblk):
131        module = Mock()
132        lh = linux.LinuxHardware(module=module, load_on_init=False)
133        lsblk_uuids = lh._lsblk_uuid()
134
135        self.assertIsInstance(lsblk_uuids, dict)
136        self.assertIn(b'/dev/loop9', lsblk_uuids)
137        self.assertIn(b'/dev/sda1', lsblk_uuids)
138        self.assertEqual(lsblk_uuids[b'/dev/sda1'], b'32caaec3-ef40-4691-a3b6-438c3f9bc1c0')
139
140    @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._run_lsblk', return_value=(37, LSBLK_OUTPUT, ''))
141    def test_lsblk_uuid_non_zero(self, mock_run_lsblk):
142        module = Mock()
143        lh = linux.LinuxHardware(module=module, load_on_init=False)
144        lsblk_uuids = lh._lsblk_uuid()
145
146        self.assertIsInstance(lsblk_uuids, dict)
147        self.assertEqual(len(lsblk_uuids), 0)
148
149    def test_lsblk_uuid_no_lsblk(self):
150        module = Mock()
151        module.get_bin_path = Mock(return_value=None)
152        lh = linux.LinuxHardware(module=module, load_on_init=False)
153        lsblk_uuids = lh._lsblk_uuid()
154
155        self.assertIsInstance(lsblk_uuids, dict)
156        self.assertEqual(len(lsblk_uuids), 0)
157
158    @patch('ansible.module_utils.facts.hardware.linux.LinuxHardware._run_lsblk', return_value=(0, LSBLK_OUTPUT_2, ''))
159    def test_lsblk_uuid_dev_with_space_in_name(self, mock_run_lsblk):
160        module = Mock()
161        lh = linux.LinuxHardware(module=module, load_on_init=False)
162        lsblk_uuids = lh._lsblk_uuid()
163        self.assertIsInstance(lsblk_uuids, dict)
164        self.assertIn(b'/dev/loop0', lsblk_uuids)
165        self.assertIn(b'/dev/sda1', lsblk_uuids)
166        self.assertEqual(lsblk_uuids[b'/dev/mapper/an-example-mapper with a space in the name'], b'84639acb-013f-4d2f-9392-526a572b4373')
167        self.assertEqual(lsblk_uuids[b'/dev/sda1'], b'32caaec3-ef40-4691-a3b6-438c3f9bc1c0')
168
169    def test_udevadm_uuid(self):
170        module = Mock()
171        module.run_command = Mock(return_value=(0, UDEVADM_OUTPUT, ''))  # (rc, out, err)
172        lh = linux.LinuxHardware(module=module, load_on_init=False)
173        udevadm_uuid = lh._udevadm_uuid('mock_device')
174
175        self.assertEqual(udevadm_uuid, '57b1a3e7-9019-4747-9809-7ec52bba9179')
176