Fixing broken bind mount on CentOS 7 (#20703)

* Fixing broken bind mount on CentOS 7
* Fixing remount
pull/21413/head
Jiri Tyr 8 years ago committed by Toshio Kuratomi
parent 65cd21e9a8
commit d94b2d802e

@ -20,9 +20,12 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'core', ANSIBLE_METADATA = {
'version': '1.0'} 'status': ['preview'],
'supported_by': 'core',
'version': '1.0'
}
DOCUMENTATION = ''' DOCUMENTATION = '''
--- ---
@ -38,7 +41,8 @@ options:
path: path:
description: description:
- Path to the mount point (e.g. C(/mnt/files)). - Path to the mount point (e.g. C(/mnt/files)).
- Before 2.3 this option was only usable as I(dest), I(destfile) and I(name). - Before 2.3 this option was only usable as I(dest), I(destfile) and
I(name).
required: true required: true
aliases: [ name ] aliases: [ name ]
src: src:
@ -90,7 +94,8 @@ options:
unless you really know what you are doing. This might be useful if unless you really know what you are doing. This might be useful if
you need to configure mountpoints in a chroot environment. OpenBSD you need to configure mountpoints in a chroot environment. OpenBSD
does not allow specifying alternate fstab files with mount so do not does not allow specifying alternate fstab files with mount so do not
use this on OpenBSD with any state that operates on the live filesystem. use this on OpenBSD with any state that operates on the live
filesystem.
required: false required: false
default: /etc/fstab (/etc/vfstab on Solaris) default: /etc/fstab (/etc/vfstab on Solaris)
boot: boot:
@ -102,7 +107,8 @@ options:
default: yes default: yes
choices: ["yes", "no"] choices: ["yes", "no"]
notes: notes:
- As of Ansible 2.3, the I(name) option has been changed to I(path) as default, but I(name) still works as well. - As of Ansible 2.3, the I(name) option has been changed to I(path) as
default, but I(name) still works as well.
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -131,14 +137,15 @@ EXAMPLES = '''
state: present state: present
''' '''
import os import os
# import module snippets
from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule, get_platform from ansible.module_utils.basic import AnsibleModule, get_platform
from ansible.module_utils.ismount import ismount from ansible.module_utils.ismount import ismount
from ansible.module_utils.pycompat24 import get_exception from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.six import iteritems from ansible.module_utils.six import iteritems
from ansible.module_utils._text import to_native
def write_fstab(lines, path): def write_fstab(lines, path):
fs_w = open(path, 'w') fs_w = open(path, 'w')
@ -317,16 +324,21 @@ def unset_mount(module, args):
return (args['name'], changed) return (args['name'], changed)
def _set_fstab_args(fstab_file): def _set_fstab_args(fstab_file):
result = [] result = []
if fstab_file and fstab_file != '/etc/fstab': if fstab_file and fstab_file != '/etc/fstab':
if get_platform().lower().endswith('bsd'): if get_platform().lower().endswith('bsd'):
result.append('-F') result.append('-F')
else: else:
result.append('-T') result.append('-T')
result.append(fstab_file) result.append(fstab_file)
return result return result
def mount(module, args): def mount(module, args):
"""Mount up a path or remount if needed.""" """Mount up a path or remount if needed."""
@ -334,14 +346,14 @@ def mount(module, args):
name = args['name'] name = args['name']
cmd = [mount_bin] cmd = [mount_bin]
if ismount(name):
return remount(module, mount_bin, args)
if get_platform().lower() == 'openbsd': if get_platform().lower() == 'openbsd':
# Use module.params['fstab'] here as args['fstab'] has been set to the # Use module.params['fstab'] here as args['fstab'] has been set to the
# default value. # default value.
if module.params['fstab'] is not None: if module.params['fstab'] is not None:
module.fail_json(msg='OpenBSD does not support alternate fstab files. Do not specify the fstab parameter for OpenBSD hosts') module.fail_json(
msg=(
'OpenBSD does not support alternate fstab files. Do not '
'specify the fstab parameter for OpenBSD hosts'))
else: else:
cmd += _set_fstab_args(args['fstab']) cmd += _set_fstab_args(args['fstab'])
@ -368,26 +380,32 @@ def umount(module, path):
else: else:
return rc, out+err return rc, out+err
def remount(module, mount_bin, args):
''' will try to use -o remount first and fallback to unmount/mount if unsupported''' def remount(module, args):
msg = '' """Try to use 'remount' first and fallback to (u)mount if unsupported."""
mount_bin = module.get_bin_path('mount', required=True)
cmd = [mount_bin] cmd = [mount_bin]
# multiplatform remount opts # Multiplatform remount opts
if get_platform().lower().endswith('bsd'): if get_platform().lower().endswith('bsd'):
cmd += ['-u'] cmd += ['-u']
else: else:
cmd += ['-o', 'remount' ] cmd += ['-o', 'remount']
if get_platform().lower() == 'openbsd': if get_platform().lower() == 'openbsd':
# Use module.params['fstab'] here as args['fstab'] has been set to the # Use module.params['fstab'] here as args['fstab'] has been set to the
# default value. # default value.
if module.params['fstab'] is not None: if module.params['fstab'] is not None:
module.fail_json(msg='OpenBSD does not support alternate fstab files. Do not specify the fstab parameter for OpenBSD hosts') module.fail_json(
msg=(
'OpenBSD does not support alternate fstab files. Do not '
'specify the fstab parameter for OpenBSD hosts'))
else: else:
cmd += _set_fstab_args(args['fstab']) cmd += _set_fstab_args(args['fstab'])
cmd += [ args['name'], ]
cmd += [args['name']]
out = err = '' out = err = ''
try: try:
if get_platform().lower().endswith('bsd'): if get_platform().lower().endswith('bsd'):
# Note: Forcing BSDs to do umount/mount due to BSD remount not # Note: Forcing BSDs to do umount/mount due to BSD remount not
@ -401,14 +419,18 @@ def remount(module, mount_bin, args):
except: except:
rc = 1 rc = 1
msg = ''
if rc != 0: if rc != 0:
msg = out + err msg = out + err
if ismount(args['name']): rc, msg = umount(module, args['name'])
rc, msg = umount(module, args['name'])
if rc == 0: if rc == 0:
rc, msg = mount(module, args) rc, msg = mount(module, args)
return rc, msg return rc, msg
# Note if we wanted to put this into module_utils we'd have to get permission # Note if we wanted to put this into module_utils we'd have to get permission
# from @jupeter -- https://github.com/ansible/ansible-modules-core/pull/2923 # from @jupeter -- https://github.com/ansible/ansible-modules-core/pull/2923
# @jtyr -- https://github.com/ansible/ansible-modules-core/issues/4439 # @jtyr -- https://github.com/ansible/ansible-modules-core/issues/4439
@ -485,90 +507,48 @@ def get_linux_mounts(module):
fields = line.split() fields = line.split()
record = { record = {
'id': int(fields[0]),
'parent_id': int(fields[1]),
'root': fields[3], 'root': fields[3],
'dst': fields[4], 'dst': fields[4],
'opts': fields[5], 'opts': fields[5],
'fields': fields[6:-4],
'fs': fields[-3], 'fs': fields[-3],
'src': fields[-2], 'src': fields[-2]
} }
mntinfo.append(record) mntinfo.append(record)
mounts = {} mounts = {}
for i, mnt in enumerate(mntinfo): for mnt in mntinfo:
src = mnt['src'] src = mnt['src']
if mnt['fs'] == 'tmpfs' and mnt['root'] != '/': if mnt['parent_id'] != 1:
# == Example: # Find parent
# 65 19 0:35 / /tmp rw shared:25 - tmpfs tmpfs rw for m in mntinfo:
# 210 65 0:35 /aaa /tmp/bbb rw shared:25 - tmpfs tmpfs rw if mnt['parent_id'] == m['id']:
# == Expected result:
# src=/tmp/aaa
# ==
shared = None
# Search for the shared field
for fld in mnt['fields']:
if fld.startswith('shared'):
shared = fld
if shared is None:
continue
dest = None
# Search fo the record with the same field
for j, m in enumerate(mntinfo):
if j < i:
if shared in m['fields']:
dest = m['dst']
else:
break
if dest is not None:
src = "%s%s" % (dest, mnt['root'])
else:
continue
elif mnt['root'] != '/' and len(mnt['fields']) > 0:
# == Example:
# 67 19 8:18 / /mnt/disk2 rw shared:26 - ext4 /dev/sdb2 rw
# 217 65 8:18 /test /tmp/ccc rw shared:26 - ext4 /dev/sdb2 rw
# == Expected result:
# src=/mnt/disk2/test
# ==
# Search for parent
for j, m in enumerate(mntinfo):
if j < i:
if m['src'] == mnt['src']:
src = "%s%s" % (m['dst'], mnt['root'])
else:
break
elif mnt['root'] != '/' and len(mnt['fields']) == 0:
# == Example 1:
# 27 20 8:1 /tmp/aaa /tmp/bbb rw - ext4 /dev/sdb2 rw
# == Example 2:
# 204 136 253:2 /rootfs / rw - ext4 /dev/sdb2 rw
# 141 140 253:2 /rootfs/tmp/aaa /tmp/bbb rw - ext4 /dev/sdb2 rw
# == Expected result:
# src=/tmp/aaa
# ==
src = mnt['root']
# Search for parent
for j, m in enumerate(mntinfo):
if j < i:
if ( if (
m['src'] == mnt['src'] and len(m['root']) > 1 and
mnt['root'].startswith(m['root'])): mnt['root'].startswith("%s/" % m['root'])):
src = src.replace("%s/" % m['root'], '/', 1) # Ommit the parent's root in the child's root
else: # == Example:
# 204 136 253:2 /rootfs / rw - ext4 /dev/sdb2 rw
# 141 140 253:2 /rootfs/tmp/aaa /tmp/bbb rw - ext4 /dev/sdb2 rw
# == Expected result:
# src=/tmp/aaa
mnt['root'] = mnt['root'][len(m['root']) + 1:]
# Prepend the parent's dst to the child's root
# == Example:
# 42 60 0:35 / /tmp rw - tmpfs tmpfs rw
# 78 42 0:35 /aaa /tmp/bbb rw - tmpfs tmpfs rw
# == Expected result:
# src=/tmp/aaa
if m['dst'] != '/':
mnt['root'] = "%s%s" % (m['dst'], mnt['root'])
src = mnt['root']
break break
mounts[mnt['dst']] = { mounts[mnt['dst']] = {
@ -602,7 +582,6 @@ def main():
) )
) )
changed = False
# solaris args: # solaris args:
# name, src, fstype, opts, boot, passno, state, fstab=/etc/vfstab # name, src, fstype, opts, boot, passno, state, fstab=/etc/vfstab
# linux args: # linux args:
@ -671,6 +650,7 @@ def main():
state = module.params['state'] state = module.params['state']
name = module.params['path'] name = module.params['path']
changed = False
if state == 'absent': if state == 'absent':
name, changed = unset_mount(module, args) name, changed = unset_mount(module, args)
@ -711,18 +691,13 @@ def main():
name, changed = set_mount(module, args) name, changed = set_mount(module, args)
res = 0 res = 0
if ismount(name): if (
ismount(name) or
is_bind_mounted(
module, linux_mounts, name, args['src'], args['fstype'])):
if changed and not module.check_mode: if changed and not module.check_mode:
res, msg = mount(module, args) res, msg = remount(module, args)
changed = True changed = True
elif 'bind' in args.get('opts', []):
changed = True
if is_bind_mounted( module, linux_mounts, name, args['src'], args['fstype']):
changed = False
if changed and not module.check_mode:
res, msg = mount(module, args)
else: else:
changed = True changed = True
@ -738,5 +713,6 @@ def main():
module.exit_json(changed=changed, **args) module.exit_json(changed=changed, **args)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

Loading…
Cancel
Save