Skip to content

Commit aa95d8a

Browse files
authored
module filesystem: partially fix idempotency issue ansible-collections#1457 (resizefs) (ansible-collections#1478)
* Use 'xfs_info' to query fs size, that doesn't always require the device be mounted. Although still query mountpoint first for backward compatibility. * Do not fail whith fstype=xfs and resizefs=yes if filesystem already fills its underlying device. * Include xfs in the tasks that test idempotency of resizefs option * Add changelogs/fragments/1478-filesystem-fix-1457-resizefs-idempotency.yml
1 parent b40a5ef commit aa95d8a

File tree

9 files changed

+65
-40
lines changed

9 files changed

+65
-40
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
bugfixes:
3+
- filesystem - do not fail when ``resizefs=yes`` and ``fstype=xfs`` if there is nothing to do, even if
4+
the filesystem is not mounted. This only covers systems supporting access to unmounted XFS filesystems.
5+
Others will still fail (https://github.com/ansible-collections/community.general/issues/1457, https://github.com/ansible-collections/community.general/pull/1478).

plugins/modules/system/filesystem.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -240,26 +240,35 @@ class XFS(Filesystem):
240240
GROW = 'xfs_growfs'
241241

242242
def get_fs_size(self, dev):
243-
cmd = self.module.get_bin_path('xfs_growfs', required=True)
244-
mountpoint = dev.get_mountpoint()
243+
cmd = self.module.get_bin_path('xfs_info', required=True)
245244

246-
if not mountpoint:
247-
# xfs filesystem needs to be mounted
248-
self.module.fail_json(msg="%s needs to be mounted for xfs operations" % dev)
245+
mountpoint = dev.get_mountpoint()
246+
if mountpoint:
247+
rc, out, err = self.module.run_command([cmd, str(mountpoint)], environ_update=self.LANG_ENV)
248+
else:
249+
# Recent GNU/Linux distros support access to unmounted XFS filesystems
250+
rc, out, err = self.module.run_command([cmd, str(dev)], environ_update=self.LANG_ENV)
251+
if rc != 0:
252+
self.module.fail_json(msg="Error while attempting to query size of XFS filesystem: %s" % err)
249253

250-
_, size, _ = self.module.run_command([cmd, '-n', str(mountpoint)], check_rc=True, environ_update=self.LANG_ENV)
251-
for line in size.splitlines():
254+
for line in out.splitlines():
252255
col = line.split('=')
253256
if col[0].strip() == 'data':
254257
if col[1].strip() != 'bsize':
255-
self.module.fail_json(msg='Unexpected output format from xfs_growfs (could not locate "bsize")')
258+
self.module.fail_json(msg='Unexpected output format from xfs_info (could not locate "bsize")')
256259
if col[2].split()[1] != 'blocks':
257-
self.module.fail_json(msg='Unexpected output format from xfs_growfs (could not locate "blocks")')
260+
self.module.fail_json(msg='Unexpected output format from xfs_info (could not locate "blocks")')
258261
block_size = int(col[2].split()[0])
259262
block_count = int(col[3].split(',')[0])
260263
return block_size * block_count
261264

262265
def grow_cmd(self, dev):
266+
# Check first if growing is needed, and then if it is doable or not.
267+
devsize_in_bytes = dev.size()
268+
fssize_in_bytes = self.get_fs_size(dev)
269+
if not fssize_in_bytes < devsize_in_bytes:
270+
self.module.exit_json(changed=False, msg="%s filesystem is using the whole device %s" % (self.fstype, dev))
271+
263272
mountpoint = dev.get_mountpoint()
264273
if not mountpoint:
265274
# xfs filesystem needs to be mounted

tests/integration/targets/filesystem/defaults/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
---
12
tested_filesystems:
23
# key: fstype
34
# fssize: size (Mo)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
---
12
dependencies:
23
- setup_pkg_mgr
34
- setup_remote_tmp_dir

tests/integration/targets/filesystem/tasks/create_device.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
---
12
- name: 'Create a "disk" file'
23
command: 'dd if=/dev/zero of={{ image_file }} bs=1M count={{ fssize }}'
34

tests/integration/targets/filesystem/tasks/create_fs.yml

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -43,40 +43,45 @@
4343
- 'fs3_result is success'
4444
- 'uuid.stdout != uuid3.stdout'
4545

46-
- name: increase fake device
47-
shell: 'dd if=/dev/zero bs=1M count=1 >> {{ image_file }}'
4846

49-
- when: fstype == 'lvm'
47+
- when: 'grow|bool and (fstype != "vfat" or resize_vfat)'
5048
block:
49+
- name: increase fake device
50+
shell: 'dd if=/dev/zero bs=1M count=1 >> {{ image_file }}'
51+
5152
- name: Resize loop device for LVM
5253
command: losetup -c {{ dev }}
54+
when: fstype == 'lvm'
5355

54-
- when: 'grow|bool and (fstype != "vfat" or resize_vfat)'
56+
- name: Expand filesystem
57+
filesystem:
58+
dev: '{{ dev }}'
59+
fstype: '{{ fstype }}'
60+
resizefs: yes
61+
register: fs4_result
62+
63+
- command: 'blkid -c /dev/null -o value -s UUID {{ dev }}'
64+
register: uuid4
65+
66+
- assert:
67+
that:
68+
- 'fs4_result is changed'
69+
- 'fs4_result is success'
70+
- 'uuid3.stdout == uuid4.stdout' # unchanged
71+
72+
- when:
73+
- (grow | bool and (fstype != "vfat" or resize_vfat)) or
74+
(fstype == "xfs" and ansible_system == "Linux" and
75+
ansible_distribution not in ["CentOS", "Ubuntu"])
5576
block:
56-
- name: Expand filesystem
57-
filesystem:
58-
dev: '{{ dev }}'
59-
fstype: '{{ fstype }}'
60-
resizefs: yes
61-
register: fs4_result
62-
63-
- command: 'blkid -c /dev/null -o value -s UUID {{ dev }}'
64-
register: uuid4
65-
66-
- assert:
67-
that:
68-
- 'fs4_result is changed'
69-
- 'fs4_result is success'
70-
- 'uuid3.stdout == uuid4.stdout' # unchanged
71-
72-
- name: Try to expand filesystem again
73-
filesystem:
74-
dev: '{{ dev }}'
75-
fstype: '{{ fstype }}'
76-
resizefs: yes
77-
register: fs5_result
78-
79-
- assert:
80-
that:
81-
- 'not (fs5_result is changed)'
82-
- 'fs5_result is successful'
77+
- name: Check that resizefs does nothing if device size is not changed
78+
filesystem:
79+
dev: '{{ dev }}'
80+
fstype: '{{ fstype }}'
81+
resizefs: yes
82+
register: fs5_result
83+
84+
- assert:
85+
that:
86+
- 'fs5_result is not changed'
87+
- 'fs5_result is succeeded'

tests/integration/targets/filesystem/tasks/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
---
12
####################################################################
23
# WARNING: These are designed specifically for Ansible tests #
34
# and should not be used as examples of how to write Ansible roles #

tests/integration/targets/filesystem/tasks/overwrite_another_fs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
---
12
- name: 'Recreate "disk" file'
23
command: 'dd if=/dev/zero of={{ image_file }} bs=1M count={{ fssize }}'
34

tests/integration/targets/filesystem/tasks/setup.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
---
12
- name: install filesystem tools
23
package:
34
name: '{{ item }}'

0 commit comments

Comments
 (0)