Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Backport 50725) mount: add fstab_{present,absent} states #54965

Merged
merged 1 commit into from
Dec 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
292 changes: 292 additions & 0 deletions salt/states/mount.py
Original file line number Diff line number Diff line change
Expand Up @@ -956,3 +956,295 @@ def mod_watch(name, user=None, **kwargs):
else:
ret['comment'] = 'Watch not supported in {0} at this time'.format(kwargs['sfun'])
return ret


def _convert_to(maybe_device, convert_to):
'''
Convert a device name, UUID or LABEL to a device name, UUID or
LABEL.

Return the fs_spec required for fstab.

'''

# Fast path. If we already have the information required, we can
# save one blkid call
if not convert_to or \
(convert_to == 'device' and maybe_device.startswith('/')) or \
maybe_device.startswith('{}='.format(convert_to.upper())):
return maybe_device

# Get the device information
if maybe_device.startswith('/'):
blkid = __salt__['disk.blkid'](maybe_device)
else:
blkid = __salt__['disk.blkid'](token=maybe_device)

result = None
if len(blkid) == 1:
if convert_to == 'device':
result = list(blkid.keys())[0]
else:
key = convert_to.upper()
result = '{}={}'.format(key, list(blkid.values())[0][key])

return result


def fstab_present(name, fs_file, fs_vfstype, fs_mntops='defaults',
fs_freq=0, fs_passno=0, mount_by=None,
config='/etc/fstab', mount=True, match_on='auto'):
'''
Makes sure that a fstab mount point is pressent.

name
The name of block device. Can be any valid fs_spec value.

fs_file
Mount point (target) for the filesystem.

fs_vfstype
The type of the filesystem (e.g. ext4, xfs, btrfs, ...)

fs_mntops
The mount options associated with the filesystem. Default is
``defaults``.

fs_freq
Field is used by dump to determine which fs need to be
dumped. Default is ``0``

fs_passno
Field is used by fsck to determine the order in which
filesystem checks are done at boot time. Default is ``0``

mount_by
Select the final value for fs_spec. Can be [``None``,
``device``, ``label``, ``uuid``, ``partlabel``,
``partuuid``]. If ``None``, the value for fs_spect will be the
parameter ``name``, in other case will search the correct
value based on the device name. For example, for ``uuid``, the
value for fs_spec will be of type 'UUID=xxx' instead of the
device name set in ``name``.

config
Place where the fstab file lives. Default is ``/etc/fstab``

mount
Set if the mount should be mounted immediately. Default is
``True``

match_on
A name or list of fstab properties on which this state should
be applied. Default is ``auto``, a special value indicating
to guess based on fstype. In general, ``auto`` matches on
name for recognized special devices and device otherwise.

'''
ret = {
'name': name,
'result': False,
'changes': {},
'comment': [],
}

# Adjust fs_mntops based on the OS
if fs_mntops == 'defaults':
if __grains__['os'] in ['MacOS', 'Darwin']:
fs_mntops = 'noowners'
elif __grains__['os'] == 'AIX':
fs_mntops = ''

# Adjust the config file based on the OS
if config == '/etc/fstab':
if __grains__['os'] in ['MacOS', 'Darwin']:
config = '/etc/auto_salt'
elif __grains__['os'] == 'AIX':
config = '/etc/filesystems'

if not fs_file == '/':
fs_file = fs_file.rstrip('/')

fs_spec = _convert_to(name, mount_by)

# Validate that the device is valid after the conversion
if not fs_spec:
msg = 'Device {} cannot be converted to {}'
ret['comment'].append(msg.format(name, mount_by))
return ret

if __opts__['test']:
if __grains__['os'] in ['MacOS', 'Darwin']:
out = __salt__['mount.set_automaster'](name=fs_file,
device=fs_spec,
fstype=fs_vfstype,
opts=fs_mntops,
config=config,
test=True)
elif __grains__['os'] == 'AIX':
out = __salt__['mount.set_filesystems'](name=fs_file,
device=fs_spec,
fstype=fs_vfstype,
opts=fs_mntops,
mount=mount,
config=config,
test=True,
match_on=match_on)
else:
out = __salt__['mount.set_fstab'](name=fs_file,
device=fs_spec,
fstype=fs_vfstype,
opts=fs_mntops,
dump=fs_freq,
pass_num=fs_passno,
config=config,
test=True,
match_on=match_on)
ret['result'] = None
if out == 'present':
msg = '{} entry is already in {}.'
ret['comment'].append(msg.format(fs_file, config))
elif out == 'new':
msg = '{} entry will be written in {}.'
ret['comment'].append(msg.format(fs_file, config))
elif out == 'change':
msg = '{} entry will be updated in {}.'
ret['comment'].append(msg.format(fs_file, config))
else:
ret['result'] = False
msg = '{} entry cannot be created in {}: {}.'
ret['comment'].append(msg.format(fs_file, config, out))
return ret

if __grains__['os'] in ['MacOS', 'Darwin']:
out = __salt__['mount.set_automaster'](name=fs_file,
device=fs_spec,
fstype=fs_vfstype,
opts=fs_mntops,
config=config)
elif __grains__['os'] == 'AIX':
out = __salt__['mount.set_filesystems'](name=fs_file,
device=fs_spec,
fstype=fs_vfstype,
opts=fs_mntops,
mount=mount,
config=config,
match_on=match_on)
else:
out = __salt__['mount.set_fstab'](name=fs_file,
device=fs_spec,
fstype=fs_vfstype,
opts=fs_mntops,
dump=fs_freq,
pass_num=fs_passno,
config=config,
match_on=match_on)

ret['result'] = True
if out == 'present':
msg = '{} entry was already in {}.'
ret['comment'].append(msg.format(fs_file, config))
elif out == 'new':
ret['changes']['persist'] = out
msg = '{} entry added in {}.'
ret['comment'].append(msg.format(fs_file, config))
elif out == 'change':
ret['changes']['persist'] = out
msg = '{} entry updated in {}.'
ret['comment'].append(msg.format(fs_file, config))
else:
ret['result'] = False
msg = '{} entry cannot be changed in {}: {}.'
ret['comment'].append(msg.format(fs_file, config, out))

return ret


def fstab_absent(name, fs_file, mount_by=None, config='/etc/fstab'):
'''
Makes sure that a fstab mount point is absent.

name
The name of block device. Can be any valid fs_spec value.

fs_file
Mount point (target) for the filesystem.

mount_by
Select the final value for fs_spec. Can be [``None``,
``device``, ``label``, ``uuid``, ``partlabel``,
``partuuid``]. If ``None``, the value for fs_spect will be the
parameter ``name``, in other case will search the correct
value based on the device name. For example, for ``uuid``, the
value for fs_spec will be of type 'UUID=xxx' instead of the
device name set in ``name``.

config
Place where the fstab file lives

'''
ret = {
'name': name,
'result': False,
'changes': {},
'comment': [],
}

# Adjust the config file based on the OS
if config == '/etc/fstab':
if __grains__['os'] in ['MacOS', 'Darwin']:
config = '/etc/auto_salt'
elif __grains__['os'] == 'AIX':
config = '/etc/filesystems'

if not fs_file == '/':
fs_file = fs_file.rstrip('/')

fs_spec = _convert_to(name, mount_by)

if __grains__['os'] in ['MacOS', 'Darwin']:
fstab_data = __salt__['mount.automaster'](config)
elif __grains__['os'] == 'AIX':
fstab_data = __salt__['mount.filesystems'](config)
else:
fstab_data = __salt__['mount.fstab'](config)

if __opts__['test']:
ret['result'] = None
if fs_file not in fstab_data:
msg = '{} entry is already missing in {}.'
ret['comment'].append(msg.format(fs_file, config))
else:
msg = '{} entry will be removed from {}.'
ret['comment'].append(msg.format(fs_file, config))
return ret

if fs_file in fstab_data:
if __grains__['os'] in ['MacOS', 'Darwin']:
out = __salt__['mount.rm_automaster'](name=fs_file,
device=fs_spec,
config=config)
elif __grains__['os'] == 'AIX':
out = __salt__['mount.rm_filesystems'](name=fs_file,
device=fs_spec,
config=config)
else:
out = __salt__['mount.rm_fstab'](name=fs_file,
device=fs_spec,
config=config)

if out is not True:
ret['result'] = False
msg = '{} entry failed when removing from {}.'
ret['comment'].append(msg.format(fs_file, config))
else:
ret['result'] = True
ret['changes']['persist'] = 'removed'
msg = '{} entry removed from {}.'
ret['comment'].append(msg.format(fs_file, config))
else:
ret['result'] = True
msg = '{} entry is already missing in {}.'
ret['comment'].append(msg.format(fs_file, config))

return ret
Loading