mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #48803 from dmurphy18/aix_filesystems
Support for execution modules and states mount on AIX
This commit is contained in:
commit
7d6b9ed0a5
5 changed files with 805 additions and 55 deletions
|
@ -17,12 +17,14 @@ import salt.utils.path
|
|||
import salt.utils.platform
|
||||
import salt.utils.mount
|
||||
import salt.utils.stringutils
|
||||
from salt.utils.odict import OrderedDict
|
||||
from salt.exceptions import CommandNotFoundError, CommandExecutionError
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
from salt.ext.six.moves import filter, zip # pylint: disable=import-error,redefined-builtin
|
||||
|
||||
|
||||
# Set up logger
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -432,6 +434,141 @@ class _vfstab_entry(object):
|
|||
return True
|
||||
|
||||
|
||||
class _FileSystemsEntry(object):
|
||||
'''
|
||||
Utility class for manipulating filesystem entries. Primarily we're parsing,
|
||||
formatting, and comparing lines. Parsing emits dicts expected from
|
||||
fstab() or raises a ValueError.
|
||||
|
||||
Note: We'll probably want to use os.normpath and os.normcase on 'name'
|
||||
'''
|
||||
|
||||
class ParseError(ValueError):
|
||||
'''
|
||||
Error raised when a line isn't parsible as an fstab entry
|
||||
'''
|
||||
|
||||
filesystems_keys = ('device', 'name', 'fstype', 'vfstype', 'opts', 'mount')
|
||||
|
||||
# preserve data format of filesystems
|
||||
compatibility_keys = ('dev', 'dev', 'name', 'fstype', 'vfstype', 'opts', 'mount', 'type', 'vfs', 'account', 'boot', 'check', 'free', 'nodename', 'quota', 'size', 'vol', 'log')
|
||||
|
||||
@classmethod
|
||||
def dict_from_lines(cls, lines, keys=filesystems_keys):
|
||||
if len(lines) < 2:
|
||||
raise ValueError('Invalid number of lines: {0}'.format(lines))
|
||||
if not keys:
|
||||
# if empty force default filesystems_keys
|
||||
keys = _FileSystemsEntry.filesystems_keys
|
||||
elif len(keys) < 6:
|
||||
raise ValueError('Invalid key name array: {0}'.format(keys))
|
||||
|
||||
blk_lines = lines
|
||||
orddict = OrderedDict()
|
||||
orddict['name'] = blk_lines[0].split(':')[0].strip()
|
||||
blk_lines.pop(0)
|
||||
for line in blk_lines:
|
||||
if line.startswith('#'):
|
||||
raise cls.ParseError("Comment!")
|
||||
|
||||
comps = line.split('= ')
|
||||
if len(comps) != 2:
|
||||
raise cls.ParseError("Invalid Entry!")
|
||||
|
||||
key_name = comps[0].strip()
|
||||
if key_name in keys:
|
||||
orddict[key_name] = comps[1].strip()
|
||||
else:
|
||||
raise ValueError('Invalid name for use in filesystems: {0}'.format(key_name))
|
||||
|
||||
return orddict
|
||||
|
||||
@classmethod
|
||||
def dict_from_cmd_line(cls, ipargs, keys):
|
||||
cmdln_dict = ipargs
|
||||
if keys:
|
||||
for key, value in keys:
|
||||
# ignore unknown or local scope keys
|
||||
if key.startswith('__'):
|
||||
continue
|
||||
if key in _FileSystemsEntry.compatibility_keys:
|
||||
cmdln_dict[key] = value
|
||||
|
||||
return cmdln_dict
|
||||
|
||||
@classmethod
|
||||
def from_line(cls, *args, **kwargs):
|
||||
return cls(** cls.dict_from_cmd_line(*args, **kwargs))
|
||||
|
||||
@classmethod
|
||||
def dict_to_lines(cls, fsys_dict_entry):
|
||||
entry = fsys_dict_entry
|
||||
strg_out = entry['name'] + ':' + os.linesep
|
||||
for k, v in six.viewitems(entry):
|
||||
if 'name' not in k:
|
||||
strg_out += '\t{0}\t\t= {1}'.format(k, v) + os.linesep
|
||||
strg_out += os.linesep
|
||||
return six.text_type(strg_out)
|
||||
|
||||
def dict_from_entry(self):
|
||||
ret = OrderedDict()
|
||||
ret[self.criteria['name']] = self.criteria
|
||||
return ret
|
||||
|
||||
def __str__(self):
|
||||
'''
|
||||
String value, only works for full repr
|
||||
'''
|
||||
return self.dict_to_lines(self.criteria)
|
||||
|
||||
def __repr__(self):
|
||||
'''
|
||||
Always works
|
||||
'''
|
||||
return repr(self.criteria)
|
||||
|
||||
def pick(self, keys):
|
||||
'''
|
||||
Returns an instance with just those keys
|
||||
'''
|
||||
subset = dict([(key, self.criteria[key]) for key in keys])
|
||||
return self.__class__(**subset)
|
||||
|
||||
def __init__(self, **criteria):
|
||||
'''
|
||||
Store non-empty, non-null values to use as filter
|
||||
'''
|
||||
items = [key_value for key_value in six.iteritems(criteria) if key_value[1] is not None]
|
||||
items = [(key_value1[0], six.text_type(key_value1[1])) for key_value1 in items]
|
||||
self.criteria = OrderedDict(items)
|
||||
|
||||
@staticmethod
|
||||
def norm_path(path):
|
||||
'''
|
||||
Resolve equivalent paths equivalently
|
||||
'''
|
||||
return os.path.normcase(os.path.normpath(path))
|
||||
|
||||
def match(self, fsys_view):
|
||||
'''
|
||||
Compare potentially partial criteria against built filesystems entry dictionary
|
||||
'''
|
||||
evalue_dict = fsys_view[1]
|
||||
for key, value in six.viewitems(self.criteria):
|
||||
if key in evalue_dict:
|
||||
if evalue_dict[key] != value:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __getitem__(self, key):
|
||||
'''
|
||||
Return value for input key
|
||||
'''
|
||||
return self.criteria[key]
|
||||
|
||||
|
||||
def fstab(config='/etc/fstab'):
|
||||
'''
|
||||
.. versionchanged:: 2016.3.2
|
||||
|
@ -1070,8 +1207,12 @@ def mount(name, device, mkmnt=False, fstype='', opts='defaults', user=None, util
|
|||
lopts = ','.join(opts)
|
||||
args = '-o {0}'.format(lopts)
|
||||
|
||||
# use of fstype on AIX is with /etc/filesystems
|
||||
if fstype and 'AIX' not in __grains__['os']:
|
||||
# use of fstype on AIX differs from typical Linux use of -t functionality
|
||||
# AIX uses -v vfsname, -t fstype mounts all with fstype in /etc/filesystems
|
||||
if 'AIX' in __grains__['os']:
|
||||
if fstype:
|
||||
args += ' -v {0}'.format(fstype)
|
||||
else:
|
||||
args += ' -t {0}'.format(fstype)
|
||||
cmd = 'mount {0} {1} {2} '.format(args, device, name)
|
||||
out = __salt__['cmd.run_all'](cmd, runas=user, python_shell=False)
|
||||
|
@ -1115,9 +1256,15 @@ def remount(name, device, mkmnt=False, fstype='', opts='defaults', user=None):
|
|||
lopts = ','.join(opts)
|
||||
args = '-o {0}'.format(lopts)
|
||||
|
||||
# use of fstype on AIX is with /etc/filesystems
|
||||
if fstype and 'AIX' not in __grains__['os']:
|
||||
# use of fstype on AIX differs from typical Linux use of -t functionality
|
||||
# AIX uses -v vfsname, -t fstype mounts all with fstype in /etc/filesystems
|
||||
if 'AIX' in __grains__['os']:
|
||||
if fstype:
|
||||
args += ' -v {0}'.format(fstype)
|
||||
args += ' -o remount'
|
||||
else:
|
||||
args += ' -t {0}'.format(fstype)
|
||||
|
||||
if __grains__['os'] not in ['OpenBSD', 'MacOS', 'Darwin'] or force_mount:
|
||||
cmd = 'mount {0} {1} {2} '.format(args, device, name)
|
||||
else:
|
||||
|
@ -1422,3 +1569,278 @@ def delete_mount_cache(real_name):
|
|||
if not cache_write:
|
||||
raise CommandExecutionError('Unable to write mount cache.')
|
||||
return True
|
||||
|
||||
|
||||
def _filesystems(config='/etc/filesystems', leading_key=True):
|
||||
'''
|
||||
Return the contents of the filesystems in an OrderedDict
|
||||
|
||||
config
|
||||
File containing filesystem infomation
|
||||
|
||||
leading_key
|
||||
True return dictionary keyed by 'name' and value as dictionary with other keys, values (name excluded)
|
||||
OrderedDict({ '/dir' : OrderedDict({'dev': '/dev/hd8', .... }}))
|
||||
|
||||
False return dictionary keyed by 'name' and value as dictionary with all keys, values (name included)
|
||||
OrderedDict({ '/dir' : OrderedDict({'name': '/dir', 'dev': '/dev/hd8', ... })})
|
||||
'''
|
||||
ret = OrderedDict()
|
||||
lines = []
|
||||
parsing_block = False
|
||||
if not os.path.isfile(config) or 'AIX' not in __grains__['kernel']:
|
||||
return ret
|
||||
|
||||
# read in block of filesystems, block starts with '/' till empty line
|
||||
with salt.utils.files.fopen(config) as ifile:
|
||||
for line in ifile:
|
||||
line = salt.utils.stringutils.to_unicode(line)
|
||||
|
||||
# skip till first entry
|
||||
if not line.startswith('/') and not parsing_block:
|
||||
continue
|
||||
|
||||
if line.startswith('/'):
|
||||
parsing_block = True
|
||||
lines.append(line)
|
||||
elif not line.split():
|
||||
parsing_block = False
|
||||
try:
|
||||
entry = _FileSystemsEntry.dict_from_lines(
|
||||
lines,
|
||||
_FileSystemsEntry.compatibility_keys)
|
||||
lines = []
|
||||
if 'opts' in entry:
|
||||
entry['opts'] = entry['opts'].split(',')
|
||||
while entry['name'] in ret:
|
||||
entry['name'] += '_'
|
||||
|
||||
if leading_key:
|
||||
ret[entry.pop('name')] = entry
|
||||
else:
|
||||
ret[entry['name']] = entry
|
||||
|
||||
except _FileSystemsEntry.ParseError:
|
||||
pass
|
||||
else:
|
||||
lines.append(line)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def filesystems(config='/etc/filesystems'):
|
||||
'''
|
||||
.. versionadded:: 2018.3.3
|
||||
|
||||
List the contents of the filesystems
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' mount.filesystems
|
||||
'''
|
||||
ret = {}
|
||||
if 'AIX' not in __grains__['kernel']:
|
||||
return ret
|
||||
|
||||
ret_dict = _filesystems(config)
|
||||
if ret_dict:
|
||||
ret_key = next(iter(ret_dict.keys()))
|
||||
ret = {ret_key: dict(ret_dict[ret_key])}
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def set_filesystems(
|
||||
name,
|
||||
device,
|
||||
vfstype,
|
||||
opts='-',
|
||||
mount='true',
|
||||
config='/etc/filesystems',
|
||||
test=False,
|
||||
match_on='auto',
|
||||
**kwargs):
|
||||
'''
|
||||
.. versionadded:: 2018.3.3
|
||||
|
||||
Verify that this mount is represented in the filesystems, change the mount
|
||||
to match the data passed, or add the mount if it is not present on AIX
|
||||
|
||||
Provide information if the path is mounted
|
||||
|
||||
:param name: The name of the mount point where the device is mounted.
|
||||
:param device: The device that is being mounted.
|
||||
:param vfstype: The file system that is used (AIX has two fstypes, fstype and vfstype - similar to Linux fstype)
|
||||
:param opts: Additional options used when mounting the device.
|
||||
:param mount: Mount if not mounted, default True.
|
||||
:param config: Configuration file, default /etc/filesystems.
|
||||
:param match: File systems type to match on, default auto
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' mount.set_filesystems /mnt/foo /dev/sdz1 jfs2
|
||||
'''
|
||||
# Fix the opts type if it is a list
|
||||
if isinstance(opts, list):
|
||||
opts = ','.join(opts)
|
||||
|
||||
# preserve arguments for updating
|
||||
entry_args = {
|
||||
'name': name,
|
||||
'dev': device.replace('\\ ', '\\040'),
|
||||
'vfstype': vfstype,
|
||||
'opts': opts,
|
||||
'mount': mount,
|
||||
}
|
||||
|
||||
view_lines = []
|
||||
ret = None
|
||||
|
||||
if 'AIX' not in __grains__['kernel']:
|
||||
return ret
|
||||
|
||||
# Transform match_on into list--items will be checked later
|
||||
if isinstance(match_on, list):
|
||||
pass
|
||||
elif not isinstance(match_on, six.string_types):
|
||||
raise CommandExecutionError('match_on must be a string or list of strings')
|
||||
elif match_on == 'auto':
|
||||
# Try to guess right criteria for auto....
|
||||
# added IBM types from sys/vmount.h after btrfs
|
||||
# NOTE: missing some special fstypes here
|
||||
specialFSes = frozenset([
|
||||
'none',
|
||||
'tmpfs',
|
||||
'sysfs',
|
||||
'proc',
|
||||
'fusectl',
|
||||
'debugfs',
|
||||
'securityfs',
|
||||
'devtmpfs',
|
||||
'cgroup',
|
||||
'btrfs',
|
||||
'cdrfs',
|
||||
'procfs',
|
||||
'jfs',
|
||||
'jfs2',
|
||||
'nfs',
|
||||
'sfs',
|
||||
'nfs3',
|
||||
'cachefs',
|
||||
'udfs',
|
||||
'cifs',
|
||||
'namefs',
|
||||
'pmemfs',
|
||||
'ahafs',
|
||||
'nfs4',
|
||||
'autofs',
|
||||
'stnfs'])
|
||||
|
||||
if vfstype in specialFSes:
|
||||
match_on = ['name']
|
||||
else:
|
||||
match_on = ['dev']
|
||||
else:
|
||||
match_on = [match_on]
|
||||
|
||||
# generate entry and criteria objects, handle invalid keys in match_on
|
||||
entry_ip = _FileSystemsEntry.from_line(entry_args, kwargs)
|
||||
try:
|
||||
criteria = entry_ip.pick(match_on)
|
||||
|
||||
except KeyError:
|
||||
filterFn = lambda key: key not in _FileSystemsEntry.compatibility_keys
|
||||
invalid_keys = filter(filterFn, match_on)
|
||||
raise CommandExecutionError('Unrecognized keys in match_on: "{0}"'.format(invalid_keys))
|
||||
|
||||
# parse file, use ret to cache status
|
||||
if not os.path.isfile(config):
|
||||
raise CommandExecutionError('Bad config file "{0}"'.format(config))
|
||||
|
||||
# read in block of filesystem, block starts with '/' till empty line
|
||||
try:
|
||||
fsys_filedict = _filesystems(config, False)
|
||||
for fsys_view in six.viewitems(fsys_filedict):
|
||||
if criteria.match(fsys_view):
|
||||
ret = 'present'
|
||||
if entry_ip.match(fsys_view):
|
||||
view_lines.append(fsys_view)
|
||||
else:
|
||||
ret = 'change'
|
||||
kv = entry_ip['name']
|
||||
view_lines.append((kv, entry_ip))
|
||||
else:
|
||||
view_lines.append(fsys_view)
|
||||
|
||||
except (IOError, OSError) as exc:
|
||||
raise CommandExecutionError('Couldn\'t read from {0}: {1}'.format(config, exc))
|
||||
|
||||
# add line if not present or changed
|
||||
if ret is None:
|
||||
for dict_view in six.viewitems(entry_ip.dict_from_entry()):
|
||||
view_lines.append(dict_view)
|
||||
ret = 'new'
|
||||
|
||||
if ret != 'present': # ret in ['new', 'change']:
|
||||
try:
|
||||
with salt.utils.files.fopen(config, 'wb') as ofile:
|
||||
# The line was changed, commit it!
|
||||
for fsys_view in view_lines:
|
||||
entry = fsys_view[1]
|
||||
mystrg = _FileSystemsEntry.dict_to_lines(entry)
|
||||
ofile.writelines(salt.utils.data.encode(mystrg))
|
||||
except (IOError, OSError):
|
||||
raise CommandExecutionError('File not writable {0}'.format(config))
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def rm_filesystems(name, device, config='/etc/filesystems'):
|
||||
'''
|
||||
.. versionadded:: 2018.3.3
|
||||
|
||||
Remove the mount point from the filesystems
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' mount.rm_filesystems /mnt/foo /dev/sdg
|
||||
'''
|
||||
modified = False
|
||||
view_lines = []
|
||||
|
||||
if 'AIX' not in __grains__['kernel']:
|
||||
return modified
|
||||
|
||||
criteria = _FileSystemsEntry(name=name, dev=device)
|
||||
try:
|
||||
fsys_filedict = _filesystems(config, False)
|
||||
for fsys_view in six.viewitems(fsys_filedict):
|
||||
try:
|
||||
if criteria.match(fsys_view):
|
||||
modified = True
|
||||
else:
|
||||
view_lines.append(fsys_view)
|
||||
|
||||
except _FileSystemsEntry.ParseError:
|
||||
view_lines.append(fsys_view)
|
||||
|
||||
except (IOError, OSError) as exc:
|
||||
raise CommandExecutionError("Couldn't read from {0}: {1}".format(config, exc))
|
||||
|
||||
if modified:
|
||||
try:
|
||||
with salt.utils.files.fopen(config, 'wb') as ofile:
|
||||
for fsys_view in view_lines:
|
||||
entry = fsys_view[1]
|
||||
mystrg = _FileSystemsEntry.dict_to_lines(entry)
|
||||
ofile.writelines(salt.utils.data.encode(mystrg))
|
||||
except (IOError, OSError) as exc:
|
||||
raise CommandExecutionError("Couldn't write to {0}: {1}".format(config, exc))
|
||||
|
||||
return modified
|
||||
|
|
|
@ -206,6 +206,11 @@ def mounted(name,
|
|||
if __grains__['os'] in ['MacOS', 'Darwin'] and opts == 'defaults':
|
||||
opts = 'noowners'
|
||||
|
||||
# Defaults is not a valid option on AIX
|
||||
if __grains__['os'] in ['AIX']:
|
||||
if opts == 'defaults':
|
||||
opts = ''
|
||||
|
||||
# Make sure that opts is correct, it can be a list or a comma delimited
|
||||
# string
|
||||
if isinstance(opts, string_types):
|
||||
|
@ -571,9 +576,14 @@ def mounted(name,
|
|||
ret['comment'] = '{0} not mounted'.format(name)
|
||||
|
||||
if persist:
|
||||
# Override default for Mac OS
|
||||
if __grains__['os'] in ['MacOS', 'Darwin'] and config == '/etc/fstab':
|
||||
config = "/etc/auto_salt"
|
||||
if '/etc/fstab' == config:
|
||||
# Override default for Mac OS
|
||||
if __grains__['os'] in ['MacOS', 'Darwin']:
|
||||
config = "/etc/auto_salt"
|
||||
|
||||
# Override default for AIX
|
||||
elif 'AIX' in __grains__['os']:
|
||||
config = "/etc/filesystems"
|
||||
|
||||
if __opts__['test']:
|
||||
if __grains__['os'] in ['MacOS', 'Darwin']:
|
||||
|
@ -583,6 +593,15 @@ def mounted(name,
|
|||
opts,
|
||||
config,
|
||||
test=True)
|
||||
elif __grains__['os'] in ['AIX']:
|
||||
out = __salt__['mount.set_filesystems'](name,
|
||||
device,
|
||||
fstype,
|
||||
opts,
|
||||
mount,
|
||||
config,
|
||||
test=True,
|
||||
match_on=match_on)
|
||||
else:
|
||||
out = __salt__['mount.set_fstab'](name,
|
||||
device,
|
||||
|
@ -631,6 +650,14 @@ def mounted(name,
|
|||
fstype,
|
||||
opts,
|
||||
config)
|
||||
elif __grains__['os'] in ['AIX']:
|
||||
out = __salt__['mount.set_filesystems'](name,
|
||||
device,
|
||||
fstype,
|
||||
opts,
|
||||
mount,
|
||||
config,
|
||||
match_on=match_on)
|
||||
else:
|
||||
out = __salt__['mount.set_fstab'](name,
|
||||
device,
|
||||
|
@ -712,7 +739,15 @@ def swap(name, persist=True, config='/etc/fstab'):
|
|||
ret['result'] = False
|
||||
|
||||
if persist:
|
||||
fstab_data = __salt__['mount.fstab'](config)
|
||||
device_key_name = 'device'
|
||||
if 'AIX' in __grains__['os']:
|
||||
device_key_name = 'dev'
|
||||
if '/etc/fstab' == config:
|
||||
# Override default for AIX
|
||||
config = "/etc/filesystems"
|
||||
fstab_data = __salt__['mount.filesystems'](config)
|
||||
else:
|
||||
fstab_data = __salt__['mount.fstab'](config)
|
||||
if __opts__['test']:
|
||||
if name not in fstab_data:
|
||||
ret['result'] = None
|
||||
|
@ -722,19 +757,25 @@ def swap(name, persist=True, config='/etc/fstab'):
|
|||
return ret
|
||||
|
||||
if 'none' in fstab_data:
|
||||
if fstab_data['none']['device'] == name and \
|
||||
if fstab_data['none'][device_key_name] == name and \
|
||||
fstab_data['none']['fstype'] != 'swap':
|
||||
return ret
|
||||
|
||||
# present, new, change, bad config
|
||||
# Make sure the entry is in the fstab
|
||||
out = __salt__['mount.set_fstab']('none',
|
||||
name,
|
||||
'swap',
|
||||
['defaults'],
|
||||
0,
|
||||
0,
|
||||
config)
|
||||
if 'AIX' in __grains__['os']:
|
||||
out = None
|
||||
ret['result'] = False
|
||||
ret['comment'] += '. swap not present in /etc/filesystems on AIX.'
|
||||
return ret
|
||||
else:
|
||||
# present, new, change, bad config
|
||||
# Make sure the entry is in the fstab
|
||||
out = __salt__['mount.set_fstab']('none',
|
||||
name,
|
||||
'swap',
|
||||
['defaults'],
|
||||
0,
|
||||
0,
|
||||
config)
|
||||
if out == 'present':
|
||||
return ret
|
||||
if out == 'new':
|
||||
|
@ -823,10 +864,16 @@ def unmounted(name,
|
|||
cache_result = __salt__['mount.delete_mount_cache'](name)
|
||||
|
||||
if persist:
|
||||
device_key_name = 'device'
|
||||
# Override default for Mac OS
|
||||
if __grains__['os'] in ['MacOS', 'Darwin'] and config == '/etc/fstab':
|
||||
config = "/etc/auto_salt"
|
||||
fstab_data = __salt__['mount.automaster'](config)
|
||||
elif 'AIX' in __grains__['os']:
|
||||
device_key_name = 'dev'
|
||||
if config == '/etc/fstab':
|
||||
config = "/etc/filesystems"
|
||||
fstab_data = __salt__['mount.filesystems'](config)
|
||||
else:
|
||||
fstab_data = __salt__['mount.fstab'](config)
|
||||
|
||||
|
@ -834,7 +881,7 @@ def unmounted(name,
|
|||
ret['comment'] += '. fstab entry not found'
|
||||
else:
|
||||
if device:
|
||||
if fstab_data[name]['device'] != device:
|
||||
if fstab_data[name][device_key_name] != device:
|
||||
ret['comment'] += '. fstab entry for device {0} not found'.format(device)
|
||||
return ret
|
||||
if __opts__['test']:
|
||||
|
@ -846,6 +893,8 @@ def unmounted(name,
|
|||
else:
|
||||
if __grains__['os'] in ['MacOS', 'Darwin']:
|
||||
out = __salt__['mount.rm_automaster'](name, device, config)
|
||||
elif 'AIX' in __grains__['os']:
|
||||
out = __salt__['mount.rm_filesystems'](name, device, config)
|
||||
else:
|
||||
out = __salt__['mount.rm_fstab'](name, device, config)
|
||||
if out is not True:
|
||||
|
|
|
@ -407,7 +407,10 @@ def flopen(*args, **kwargs):
|
|||
with fopen(*args, **kwargs) as f_handle:
|
||||
try:
|
||||
if is_fcntl_available(check_sunos=True):
|
||||
fcntl.flock(f_handle.fileno(), fcntl.LOCK_SH)
|
||||
lock_type = fcntl.LOCK_SH
|
||||
if 'w' in args[1] or 'a' in args[1]:
|
||||
lock_type = fcntl.LOCK_EX
|
||||
fcntl.flock(f_handle.fileno(), lock_type)
|
||||
yield f_handle
|
||||
finally:
|
||||
if is_fcntl_available(check_sunos=True):
|
||||
|
|
|
@ -79,6 +79,11 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
with patch.object(mount, '_active_mounts_darwin', mock):
|
||||
self.assertEqual(mount.active(extended=True), {})
|
||||
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX', 'kernel': 'AIX'}):
|
||||
mock = MagicMock(return_value={})
|
||||
with patch.object(mount, '_active_mounts_aix', mock):
|
||||
self.assertEqual(mount.active(), {})
|
||||
|
||||
def test_fstab(self):
|
||||
'''
|
||||
List the content of the fstab
|
||||
|
@ -127,6 +132,48 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
'pass_fsck': '-'}
|
||||
}, vfstab
|
||||
|
||||
def test_filesystems(self):
|
||||
'''
|
||||
List the content of the filesystems
|
||||
'''
|
||||
file_data = textwrap.dedent('''\
|
||||
#
|
||||
|
||||
''')
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX', 'kernel': 'AIX'}), \
|
||||
patch.object(os.path, 'isfile', mock), \
|
||||
patch('salt.utils.files.fopen', mock_open(read_data=file_data)):
|
||||
self.assertEqual(mount.filesystems(), {})
|
||||
|
||||
file_data = textwrap.dedent('''\
|
||||
#
|
||||
/home:
|
||||
dev = /dev/hd1
|
||||
vfs = jfs2
|
||||
log = /dev/hd8
|
||||
mount = true
|
||||
check = true
|
||||
vol = /home
|
||||
free = false
|
||||
quota = no
|
||||
|
||||
''')
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX', 'kernel': 'AIX'}), \
|
||||
patch.object(os.path, 'isfile', mock), \
|
||||
patch('salt.utils.files.fopen', mock_open(read_data=file_data)):
|
||||
fsyst = mount.filesystems()
|
||||
test_fsyst = {'/home': {'dev': '/dev/hd1',
|
||||
'vfs': 'jfs2',
|
||||
'log': '/dev/hd8',
|
||||
'mount': 'true',
|
||||
'check': 'true',
|
||||
'vol': '/home',
|
||||
'free': 'false',
|
||||
'quota': 'no'}}
|
||||
self.assertEqual(test_fsyst, fsyst)
|
||||
|
||||
def test_rm_fstab(self):
|
||||
'''
|
||||
Remove the mount point from the fstab
|
||||
|
@ -190,6 +237,53 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
'''
|
||||
self.assertDictEqual(mount.automaster(), {})
|
||||
|
||||
def test_rm_filesystems(self):
|
||||
'''
|
||||
Remove the mount point from the filesystems
|
||||
'''
|
||||
file_data = textwrap.dedent('''\
|
||||
#
|
||||
|
||||
''')
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX', 'kernel': 'AIX'}), \
|
||||
patch.object(os.path, 'isfile', mock), \
|
||||
patch('salt.utils.files.fopen', mock_open(read_data=file_data)):
|
||||
self.assertFalse(mount.rm_filesystems('name', 'device'))
|
||||
|
||||
file_data = textwrap.dedent('''\
|
||||
#
|
||||
/name:
|
||||
dev = device
|
||||
vol = /name
|
||||
|
||||
''')
|
||||
|
||||
mock = MagicMock(return_value=True)
|
||||
mock_fsyst = MagicMock(return_value=True)
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX', 'kernel': 'AIX'}), \
|
||||
patch.object(os.path, 'isfile', mock), \
|
||||
patch('salt.utils.files.fopen', mock_open(read_data=file_data)):
|
||||
self.assertTrue(mount.rm_filesystems('/name', 'device'))
|
||||
|
||||
def test_set_filesystems(self):
|
||||
'''
|
||||
Tests to verify that this mount is represented in the filesystems,
|
||||
change the mount to match the data passed, or add the mount
|
||||
if it is not present.
|
||||
'''
|
||||
mock = MagicMock(return_value=False)
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX', 'kernel': 'AIX'}):
|
||||
with patch.object(os.path, 'isfile', mock):
|
||||
self.assertRaises(CommandExecutionError,
|
||||
mount.set_filesystems, 'A', 'B', 'C')
|
||||
|
||||
mock_read = MagicMock(side_effect=OSError)
|
||||
with patch.object(os.path, 'isfile', mock):
|
||||
with patch.object(salt.utils.files, 'fopen', mock_read):
|
||||
self.assertRaises(CommandExecutionError,
|
||||
mount.set_filesystems, 'A', 'B', 'C')
|
||||
|
||||
def test_mount(self):
|
||||
'''
|
||||
Mount a device
|
||||
|
@ -209,6 +303,21 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(mount.__salt__, {'cmd.run_all': mock}):
|
||||
self.assertTrue(mount.mount('name', 'device'))
|
||||
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX'}):
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.object(os.path, 'exists', mock):
|
||||
mock = MagicMock(return_value=None)
|
||||
with patch.dict(mount.__salt__, {'file.mkdir': None}):
|
||||
mock = MagicMock(return_value={'retcode': True,
|
||||
'stderr': True})
|
||||
with patch.dict(mount.__salt__, {'cmd.run_all': mock}):
|
||||
self.assertTrue(mount.mount('name', 'device'))
|
||||
|
||||
mock = MagicMock(return_value={'retcode': False,
|
||||
'stderr': False})
|
||||
with patch.dict(mount.__salt__, {'cmd.run_all': mock}):
|
||||
self.assertTrue(mount.mount('name', 'device'))
|
||||
|
||||
def test_remount(self):
|
||||
'''
|
||||
Attempt to remount a device, if the device is not already mounted, mount
|
||||
|
@ -221,6 +330,13 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
with patch.object(mount, 'mount', mock):
|
||||
self.assertTrue(mount.remount('name', 'device'))
|
||||
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX'}):
|
||||
mock = MagicMock(return_value=[])
|
||||
with patch.object(mount, 'active', mock):
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.object(mount, 'mount', mock):
|
||||
self.assertTrue(mount.remount('name', 'device'))
|
||||
|
||||
def test_umount(self):
|
||||
'''
|
||||
Attempt to unmount a device by specifying the directory it is
|
||||
|
@ -274,7 +390,6 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
'''
|
||||
Return a dict containing information on active swap
|
||||
'''
|
||||
|
||||
file_data = textwrap.dedent('''\
|
||||
Filename Type Size Used Priority
|
||||
/dev/sda1 partition 31249404 4100 -1
|
||||
|
@ -306,6 +421,22 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
'used': '4100'}
|
||||
}, swaps
|
||||
|
||||
file_data = textwrap.dedent('''\
|
||||
device maj,min total free
|
||||
/dev/hd6 10, 2 11776MB 11765MB
|
||||
''')
|
||||
mock = MagicMock(return_value=file_data)
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX', 'kernel': 'AIX'}), \
|
||||
patch.dict(mount.__salt__, {'cmd.run_stdout': mock}):
|
||||
swaps = mount.swaps()
|
||||
assert swaps == {
|
||||
'/dev/hd6': {
|
||||
'priority': '-',
|
||||
'size': 12058624,
|
||||
'type': 'device',
|
||||
'used': 11264}
|
||||
}, swaps
|
||||
|
||||
def test_swapon(self):
|
||||
'''
|
||||
Activate a swap disk
|
||||
|
@ -330,6 +461,27 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(mount.__salt__, {'cmd.run': mock}):
|
||||
self.assertEqual(mount.swapon('name'), {'stats': 'name',
|
||||
'new': True})
|
||||
## effects of AIX
|
||||
mock = MagicMock(return_value={'name': 'name'})
|
||||
with patch.dict(mount.__grains__, {'kernel': 'AIX'}):
|
||||
with patch.object(mount, 'swaps', mock):
|
||||
self.assertEqual(mount.swapon('name'),
|
||||
{'stats': 'name', 'new': False})
|
||||
|
||||
mock = MagicMock(return_value={})
|
||||
with patch.dict(mount.__grains__, {'kernel': 'AIX'}):
|
||||
with patch.object(mount, 'swaps', mock):
|
||||
mock = MagicMock(return_value=None)
|
||||
with patch.dict(mount.__salt__, {'cmd.run': mock}):
|
||||
self.assertEqual(mount.swapon('name', False), {})
|
||||
|
||||
mock = MagicMock(side_effect=[{}, {'name': 'name'}])
|
||||
with patch.dict(mount.__grains__, {'kernel': 'AIX'}):
|
||||
with patch.object(mount, 'swaps', mock):
|
||||
mock = MagicMock(return_value=None)
|
||||
with patch.dict(mount.__salt__, {'cmd.run': mock}):
|
||||
self.assertEqual(mount.swapon('name'), {'stats': 'name',
|
||||
'new': True})
|
||||
|
||||
def test_swapoff(self):
|
||||
'''
|
||||
|
@ -356,14 +508,38 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(mount.__salt__, {'cmd.run': mock}):
|
||||
self.assertTrue(mount.swapoff('name'))
|
||||
|
||||
# check on AIX
|
||||
mock = MagicMock(return_value={})
|
||||
with patch.dict(mount.__grains__, {'kernel': 'AIX'}):
|
||||
with patch.object(mount, 'swaps', mock):
|
||||
self.assertEqual(mount.swapoff('name'), None)
|
||||
|
||||
mock = MagicMock(return_value={'name': 'name'})
|
||||
with patch.dict(mount.__grains__, {'kernel': 'AIX'}):
|
||||
with patch.object(mount, 'swaps', mock):
|
||||
with patch.dict(mount.__grains__, {'os': 'test'}):
|
||||
mock = MagicMock(return_value=None)
|
||||
with patch.dict(mount.__salt__, {'cmd.run': mock}):
|
||||
self.assertFalse(mount.swapoff('name'))
|
||||
|
||||
mock = MagicMock(side_effect=[{'name': 'name'}, {}])
|
||||
with patch.dict(mount.__grains__, {'kernel': 'AIX'}):
|
||||
with patch.object(mount, 'swaps', mock):
|
||||
with patch.dict(mount.__grains__, {'os': 'test'}):
|
||||
mock = MagicMock(return_value=None)
|
||||
with patch.dict(mount.__salt__, {'cmd.run': mock}):
|
||||
self.assertTrue(mount.swapoff('name'))
|
||||
|
||||
def test_is_mounted(self):
|
||||
'''
|
||||
Provide information if the path is mounted
|
||||
'''
|
||||
mock = MagicMock(return_value={})
|
||||
with patch.object(mount, 'active', mock):
|
||||
with patch.object(mount, 'active', mock), \
|
||||
patch.dict(mount.__grains__, {'kernel': ''}):
|
||||
self.assertFalse(mount.is_mounted('name'))
|
||||
|
||||
mock = MagicMock(return_value={'name': 'name'})
|
||||
with patch.object(mount, 'active', mock):
|
||||
with patch.object(mount, 'active', mock), \
|
||||
patch.dict(mount.__grains__, {'kernel': ''}):
|
||||
self.assertTrue(mount.is_mounted('name'))
|
||||
|
|
|
@ -44,6 +44,13 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
superopts2 = ['uid=510', 'gid=100', 'username=cifsuser',
|
||||
'domain=cifsdomain']
|
||||
|
||||
name3 = os.path.realpath('/mnt/jfs2')
|
||||
device3 = '/dev/hd1'
|
||||
fstype3 = 'jfs2'
|
||||
opts3 = ['']
|
||||
superopts3 = ['uid=510', 'gid=100', 'username=jfs2user',
|
||||
'domain=jfs2sdomain']
|
||||
|
||||
ret = {'name': name,
|
||||
'result': False,
|
||||
'comment': '',
|
||||
|
@ -57,7 +64,11 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
mock_mnt = MagicMock(return_value={name: {'device': device, 'opts': [],
|
||||
'superopts': []},
|
||||
name2: {'device': device2, 'opts': opts2,
|
||||
'superopts': superopts2}})
|
||||
'superopts': superopts2},
|
||||
name3: {'device': device3, 'opts': opts3,
|
||||
'superopts': superopts3}})
|
||||
mock_aixfs_retn = MagicMock(return_value='present')
|
||||
|
||||
mock_emt = MagicMock(return_value={})
|
||||
mock_str = MagicMock(return_value='salt')
|
||||
mock_user = MagicMock(return_value={'uid': 510})
|
||||
|
@ -91,7 +102,8 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
ret)
|
||||
|
||||
umount1 = ("Forced unmount because devices don't match. "
|
||||
"Wanted: {0}, current: {1}, {1}".format(os.path.realpath('/dev/sdb6'), device))
|
||||
"Wanted: {0}, current: {1}, {1}"
|
||||
.format(os.path.realpath('/dev/sdb6'), device))
|
||||
comt = ('Unable to unmount')
|
||||
ret.update({'comment': comt, 'result': None,
|
||||
'changes': {'umount': umount1}})
|
||||
|
@ -124,7 +136,8 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(mount.__opts__, {'test': True}), \
|
||||
patch('os.path.exists', MagicMock(return_value=False)):
|
||||
comt = ('{0} does not exist and would neither be created nor mounted. '
|
||||
'{0} needs to be written to the fstab in order to be made persistent.'.format(name))
|
||||
'{0} needs to be written to the fstab in order to be made persistent.'
|
||||
.format(name))
|
||||
ret.update({'comment': comt, 'result': None})
|
||||
self.assertDictEqual(mount.mounted(name, device, fstype,
|
||||
mount=False), ret)
|
||||
|
@ -185,6 +198,26 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
'gid=group1']),
|
||||
ret)
|
||||
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX'}):
|
||||
with patch.dict(mount.__salt__, {'mount.active': mock_mnt,
|
||||
'mount.mount': mock_str,
|
||||
'mount.umount': mock_f,
|
||||
'mount.read_mount_cache': mock_read_cache,
|
||||
'mount.write_mount_cache': mock_write_cache,
|
||||
'mount.set_filesystems': mock_aixfs_retn,
|
||||
'user.info': mock_user,
|
||||
'group.info': mock_group}):
|
||||
with patch.dict(mount.__opts__, {'test': True}):
|
||||
with patch.object(os.path, 'exists', mock_t):
|
||||
comt = 'Target was already mounted. Entry already exists in the fstab.'
|
||||
ret.update({'name': name3, 'result': True})
|
||||
ret.update({'comment': comt, 'changes': {}})
|
||||
self.assertDictEqual(mount.mounted(name3, device3,
|
||||
fstype3,
|
||||
opts=['uid=user1',
|
||||
'gid=group1']),
|
||||
ret)
|
||||
|
||||
# 'swap' function tests: 1
|
||||
|
||||
def test_swap(self):
|
||||
|
@ -203,44 +236,69 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
mock_swp = MagicMock(return_value=[name])
|
||||
mock_fs = MagicMock(return_value={'none': {'device': name,
|
||||
'fstype': 'xfs'}})
|
||||
mock_aixfs = MagicMock(return_value={name: {'dev': name,
|
||||
'fstype': 'jfs2'}})
|
||||
mock_emt = MagicMock(return_value={})
|
||||
with patch.dict(mount.__salt__, {'mount.swaps': mock_swp,
|
||||
'mount.fstab': mock_fs,
|
||||
'file.is_link': mock_f}):
|
||||
with patch.dict(mount.__opts__, {'test': True}):
|
||||
comt = ('Swap {0} is set to be added to the '
|
||||
'fstab and to be activated'.format(name))
|
||||
ret.update({'comment': comt})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
with patch.dict(mount.__grains__, {'os': 'test'}):
|
||||
with patch.dict(mount.__salt__, {'mount.swaps': mock_swp,
|
||||
'mount.fstab': mock_fs,
|
||||
'file.is_link': mock_f}):
|
||||
with patch.dict(mount.__opts__, {'test': True}):
|
||||
comt = ('Swap {0} is set to be added to the '
|
||||
'fstab and to be activated'.format(name))
|
||||
ret.update({'comment': comt})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
|
||||
with patch.dict(mount.__opts__, {'test': False}):
|
||||
comt = ('Swap {0} already active'.format(name))
|
||||
ret.update({'comment': comt, 'result': True})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
|
||||
with patch.dict(mount.__salt__, {'mount.fstab': mock_emt,
|
||||
'mount.set_fstab': mock}):
|
||||
with patch.dict(mount.__opts__, {'test': False}):
|
||||
comt = ('Swap {0} already active'.format(name))
|
||||
ret.update({'comment': comt, 'result': True})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
|
||||
comt = ('Swap /mnt/sdb already active. '
|
||||
'Added new entry to the fstab.')
|
||||
ret.update({'comment': comt, 'result': True,
|
||||
'changes': {'persist': 'new'}})
|
||||
with patch.dict(mount.__salt__, {'mount.fstab': mock_emt,
|
||||
'mount.set_fstab': mock}):
|
||||
comt = ('Swap {0} already active'.format(name))
|
||||
ret.update({'comment': comt, 'result': True})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
|
||||
comt = ('Swap /mnt/sdb already active. '
|
||||
'Added new entry to the fstab.')
|
||||
ret.update({'comment': comt, 'result': True,
|
||||
'changes': {'persist': 'new'}})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
|
||||
comt = ('Swap /mnt/sdb already active. '
|
||||
'Updated the entry in the fstab.')
|
||||
ret.update({'comment': comt, 'result': True,
|
||||
'changes': {'persist': 'update'}})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
|
||||
comt = ('Swap /mnt/sdb already active. '
|
||||
'However, the fstab was not found.')
|
||||
ret.update({'comment': comt, 'result': False,
|
||||
'changes': {}})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX'}):
|
||||
with patch.dict(mount.__salt__, {'mount.swaps': mock_swp,
|
||||
'mount.filesystems': mock_aixfs,
|
||||
'file.is_link': mock_f}):
|
||||
with patch.dict(mount.__opts__, {'test': True}):
|
||||
comt = ('Swap {0} already active'.format(name))
|
||||
ret.update({'comment': comt, 'result': True})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
|
||||
comt = ('Swap /mnt/sdb already active. '
|
||||
'Updated the entry in the fstab.')
|
||||
ret.update({'comment': comt, 'result': True,
|
||||
'changes': {'persist': 'update'}})
|
||||
with patch.dict(mount.__opts__, {'test': False}):
|
||||
comt = ('Swap {0} already active. swap not present'
|
||||
' in /etc/filesystems on AIX.'.format(name))
|
||||
ret.update({'comment': comt, 'result': False})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
|
||||
comt = ('Swap /mnt/sdb already active. '
|
||||
'However, the fstab was not found.')
|
||||
ret.update({'comment': comt, 'result': False,
|
||||
'changes': {}})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
with patch.dict(mount.__salt__, {'mount.filesystems': mock_emt,
|
||||
'mount.set_filesystems': mock}):
|
||||
comt = ('Swap {0} already active. swap not present'
|
||||
' in /etc/filesystems on AIX.'.format(name))
|
||||
ret.update({'comment': comt, 'result': False})
|
||||
self.assertDictEqual(mount.swap(name), ret)
|
||||
|
||||
# 'unmounted' function tests: 1
|
||||
|
||||
|
@ -257,11 +315,22 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
'changes': {}}
|
||||
|
||||
mock_f = MagicMock(return_value=False)
|
||||
mock_t = MagicMock(return_value=True)
|
||||
mock_dev = MagicMock(return_value={name: {'device': device}})
|
||||
mock_fs = MagicMock(return_value={name: {'device': name}})
|
||||
mock_mnt = MagicMock(side_effect=[{name: {}}, {}, {}, {}])
|
||||
|
||||
name3 = os.path.realpath('/mnt/jfs2')
|
||||
device3 = '/dev/hd1'
|
||||
fstype3 = 'jfs2'
|
||||
opts3 = ['']
|
||||
mock_mnta = MagicMock(return_value={name3: {'device': device3, 'opts': opts3}})
|
||||
mock_aixfs = MagicMock(return_value={name: {'dev': name3, 'fstype': fstype3}})
|
||||
mock_delete_cache = MagicMock(return_value=True)
|
||||
|
||||
comt3 = ('Mount point /mnt/sdb is unmounted but needs to be purged '
|
||||
'from /etc/auto_salt to be made persistent')
|
||||
|
||||
with patch.dict(mount.__grains__, {'os': 'Darwin'}):
|
||||
with patch.dict(mount.__salt__, {'mount.active': mock_mnt,
|
||||
'mount.automaster': mock_fs,
|
||||
|
@ -273,7 +342,7 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
self.assertDictEqual(mount.unmounted(name, device), ret)
|
||||
|
||||
comt = ('Target was already unmounted. '
|
||||
'fstab entry for device /dev/sdb5 not found')
|
||||
'fstab entry for device {0} not found'.format(device))
|
||||
ret.update({'comment': comt, 'result': True})
|
||||
self.assertDictEqual(mount.unmounted(name, device,
|
||||
persist=True), ret)
|
||||
|
@ -288,6 +357,37 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
|
|||
ret.update({'comment': comt, 'result': True})
|
||||
self.assertDictEqual(mount.unmounted(name, device), ret)
|
||||
|
||||
with patch.dict(mount.__grains__, {'os': 'AIX'}):
|
||||
with patch.dict(mount.__salt__, {'mount.active': mock_mnta,
|
||||
'mount.filesystems': mock_aixfs,
|
||||
'file.is_link': mock_f}):
|
||||
with patch.dict(mount.__opts__, {'test': True}):
|
||||
comt = ('Target was already unmounted')
|
||||
ret.update({'comment': comt, 'result': True})
|
||||
self.assertDictEqual(mount.unmounted(name, device), ret)
|
||||
|
||||
comt = ('Target was already unmounted. '
|
||||
'fstab entry for device /dev/sdb5 not found')
|
||||
ret.update({'comment': comt, 'result': True})
|
||||
self.assertDictEqual(mount.unmounted(name, device,
|
||||
persist=True), ret)
|
||||
|
||||
with patch.dict(mount.__salt__,
|
||||
{'mount.filesystems': mock_dev}):
|
||||
comt = ('Mount point {0} is mounted but should not '
|
||||
'be'.format(name3))
|
||||
ret.update({'comment': comt, 'result': None, 'name': name3})
|
||||
self.assertDictEqual(mount.unmounted(name3, device3,
|
||||
persist=True), ret)
|
||||
|
||||
with patch.dict(mount.__opts__, {'test': False}), \
|
||||
patch.dict(mount.__salt__, {'mount.umount': mock_t,
|
||||
'mount.delete_mount_cache': mock_delete_cache}):
|
||||
comt = ('Target was successfully unmounted')
|
||||
ret.update({'comment': comt, 'result': True,
|
||||
'name': name3, 'changes': {'umount': True}})
|
||||
self.assertDictEqual(mount.unmounted(name3, device3), ret)
|
||||
|
||||
# 'mod_watch' function tests: 1
|
||||
|
||||
def test_mod_watch(self):
|
||||
|
|
Loading…
Add table
Reference in a new issue