|
|
@ -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'],
|
|
|
|
|
|
|
|
|
|
|
|
ANSIBLE_METADATA = {
|
|
|
|
|
|
|
|
'status': ['preview'],
|
|
|
|
'supported_by': 'core',
|
|
|
|
'supported_by': 'core',
|
|
|
|
'version': '1.0'}
|
|
|
|
'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:
|
|
|
|
|
|
|
|
# Find parent
|
|
|
|
|
|
|
|
for m in mntinfo:
|
|
|
|
|
|
|
|
if mnt['parent_id'] == m['id']:
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
|
|
len(m['root']) > 1 and
|
|
|
|
|
|
|
|
mnt['root'].startswith("%s/" % m['root'])):
|
|
|
|
|
|
|
|
# Ommit the parent's root in the child's root
|
|
|
|
# == Example:
|
|
|
|
# == Example:
|
|
|
|
# 65 19 0:35 / /tmp rw shared:25 - tmpfs tmpfs rw
|
|
|
|
# 204 136 253:2 /rootfs / rw - ext4 /dev/sdb2 rw
|
|
|
|
# 210 65 0:35 /aaa /tmp/bbb rw shared:25 - tmpfs tmpfs rw
|
|
|
|
# 141 140 253:2 /rootfs/tmp/aaa /tmp/bbb rw - ext4 /dev/sdb2 rw
|
|
|
|
# == Expected result:
|
|
|
|
# == Expected result:
|
|
|
|
# src=/tmp/aaa
|
|
|
|
# src=/tmp/aaa
|
|
|
|
# ==
|
|
|
|
mnt['root'] = mnt['root'][len(m['root']) + 1:]
|
|
|
|
|
|
|
|
|
|
|
|
shared = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Search for the shared field
|
|
|
|
|
|
|
|
for fld in mnt['fields']:
|
|
|
|
|
|
|
|
if fld.startswith('shared'):
|
|
|
|
|
|
|
|
shared = fld
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if shared is None:
|
|
|
|
# Prepend the parent's dst to the child's root
|
|
|
|
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:
|
|
|
|
# == Example:
|
|
|
|
# 67 19 8:18 / /mnt/disk2 rw shared:26 - ext4 /dev/sdb2 rw
|
|
|
|
# 42 60 0:35 / /tmp rw - tmpfs tmpfs rw
|
|
|
|
# 217 65 8:18 /test /tmp/ccc rw shared:26 - ext4 /dev/sdb2 rw
|
|
|
|
# 78 42 0:35 /aaa /tmp/bbb rw - tmpfs tmpfs 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:
|
|
|
|
# == Expected result:
|
|
|
|
# src=/tmp/aaa
|
|
|
|
# src=/tmp/aaa
|
|
|
|
# ==
|
|
|
|
if m['dst'] != '/':
|
|
|
|
|
|
|
|
mnt['root'] = "%s%s" % (m['dst'], mnt['root'])
|
|
|
|
|
|
|
|
|
|
|
|
src = mnt['root']
|
|
|
|
src = mnt['root']
|
|
|
|
|
|
|
|
|
|
|
|
# Search for parent
|
|
|
|
|
|
|
|
for j, m in enumerate(mntinfo):
|
|
|
|
|
|
|
|
if j < i:
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
|
|
m['src'] == mnt['src'] and
|
|
|
|
|
|
|
|
mnt['root'].startswith(m['root'])):
|
|
|
|
|
|
|
|
src = src.replace("%s/" % m['root'], '/', 1)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
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()
|
|
|
|