diff --git a/salt/modules/file.py b/salt/modules/file.py index 30f4191904..d51cea8616 100644 --- a/salt/modules/file.py +++ b/salt/modules/file.py @@ -195,7 +195,7 @@ def get_gid(path, follow_symlinks=True): .. versionchanged:: 0.16.4 ``follow_symlinks`` option added ''' - return stats(path, follow_symlinks=follow_symlinks).get('gid', -1) + return stats(os.path.expanduser(path), follow_symlinks=follow_symlinks).get('gid', -1) def get_group(path, follow_symlinks=True): @@ -217,7 +217,7 @@ def get_group(path, follow_symlinks=True): .. versionchanged:: 0.16.4 ``follow_symlinks`` option added ''' - return stats(path, follow_symlinks=follow_symlinks).get('group', False) + return stats(os.path.expanduser(path), follow_symlinks=follow_symlinks).get('group', False) def uid_to_user(uid): @@ -281,7 +281,7 @@ def get_uid(path, follow_symlinks=True): .. versionchanged:: 0.16.4 ``follow_symlinks`` option added ''' - return stats(path, follow_symlinks=follow_symlinks).get('uid', -1) + return stats(os.path.expanduser(path), follow_symlinks=follow_symlinks).get('uid', -1) def get_user(path, follow_symlinks=True): @@ -303,7 +303,7 @@ def get_user(path, follow_symlinks=True): .. versionchanged:: 0.16.4 ``follow_symlinks`` option added ''' - return stats(path, follow_symlinks=follow_symlinks).get('user', False) + return stats(os.path.expanduser(path), follow_symlinks=follow_symlinks).get('user', False) def get_mode(path, follow_symlinks=True): @@ -325,7 +325,7 @@ def get_mode(path, follow_symlinks=True): .. versionchanged:: 2014.1.0 ``follow_symlinks`` option added ''' - return stats(path, follow_symlinks=follow_symlinks).get('mode', '') + return stats(os.path.expanduser(path), follow_symlinks=follow_symlinks).get('mode', '') def set_mode(path, mode): @@ -344,6 +344,8 @@ def set_mode(path, mode): salt '*' file.set_mode /etc/passwd 0644 ''' + path = os.path.expanduser(path) + mode = str(mode).lstrip('0') if not mode: mode = '0' @@ -376,6 +378,8 @@ def lchown(path, user, group): salt '*' file.chown /etc/passwd root root ''' + path = os.path.expanduser(path) + uid = user_to_uid(user) gid = group_to_gid(group) err = '' @@ -412,6 +416,8 @@ def chown(path, user, group): salt '*' file.chown /etc/passwd root root ''' + path = os.path.expanduser(path) + uid = user_to_uid(user) gid = group_to_gid(group) err = '' @@ -453,6 +459,8 @@ def chgrp(path, group): salt '*' file.chgrp /etc/passwd root ''' + path = os.path.expanduser(path) + user = get_user(path) return chown(path, user, group) @@ -474,6 +482,8 @@ def get_sum(path, form='sha256'): salt '*' file.get_sum /etc/passwd sha512 ''' + path = os.path.expanduser(path) + if not os.path.isfile(path): return 'File not found' return salt.utils.get_hash(path, form, 4096) @@ -504,7 +514,7 @@ def get_hash(path, form='sha256', chunk_size=65536): salt '*' file.get_hash /etc/shadow ''' - return salt.utils.get_hash(path, form, chunk_size) + return salt.utils.get_hash(os.path.expanduser(path), form, chunk_size) def check_hash(path, file_hash): @@ -526,6 +536,8 @@ def check_hash(path, file_hash): salt '*' file.check_hash /etc/fstab md5: ''' + path = os.path.expanduser(path) + hash_parts = file_hash.split(':', 1) if len(hash_parts) != 2: # Support "=" for backward compatibility. @@ -648,7 +660,7 @@ def find(path, **kwargs): except ValueError as ex: return 'error: {0}'.format(ex) - ret = [p for p in finder.find(path)] + ret = [p for p in finder.find(os.path.expanduser(path))] ret.sort() return ret @@ -720,6 +732,7 @@ def sed(path, # Largely inspired by Fabric's contrib.files.sed() # XXX:dc: Do we really want to always force escaping? # + path = os.path.expanduser(path) if not os.path.exists(path): return False @@ -770,6 +783,7 @@ def sed_contains(path, salt '*' file.contains /etc/crontab 'mymaintenance.sh' ''' # Largely inspired by Fabric's contrib.files.contains() + path = os.path.expanduser(path) if not os.path.exists(path): return False @@ -851,6 +865,8 @@ def psed(path, # XXX:dc: Do we really want to always force escaping? # # Mandate that before and after are strings + path = os.path.expanduser(path) + multi = bool(multi) before = str(before) @@ -1120,6 +1136,8 @@ def replace(path, salt '*' file.replace /etc/httpd/httpd.conf 'LogLevel warn' 'LogLevel info' salt '*' file.replace /some/file 'before' 'after' flags='[MULTILINE, IGNORECASE]' ''' + path = os.path.expanduser(path) + if not os.path.exists(path): raise SaltInvocationError('File not found: {0}'.format(path)) @@ -1289,6 +1307,8 @@ def blockreplace(path, '#-- end managed zone foobar --' $'10.0.1.1 foo.foobar\\n10.0.1.2 bar.foobar' True ''' + path = os.path.expanduser(path) + if not os.path.exists(path): raise SaltInvocationError('File not found: {0}'.format(path)) @@ -1501,6 +1521,8 @@ def contains(path, text): salt '*' file.contains /etc/crontab 'mymaintenance.sh' ''' + path = os.path.expanduser(path) + if not os.path.exists(path): return False @@ -1532,6 +1554,8 @@ def contains_regex(path, regex, lchar=''): salt '*' file.contains_regex /etc/crontab ''' + path = os.path.expanduser(path) + if not os.path.exists(path): return False @@ -1564,6 +1588,8 @@ def contains_regex_multiline(path, regex): salt '*' file.contains_regex_multiline /etc/crontab '^maint' ''' + path = os.path.expanduser(path) + if not os.path.exists(path): return False @@ -1590,6 +1616,8 @@ def contains_glob(path, glob_expr): salt '*' file.contains_glob /etc/foobar '*cheese*' ''' + path = os.path.expanduser(path) + if not os.path.exists(path): return False @@ -1636,6 +1664,8 @@ def append(path, *args, **kwargs): salt '*' file.append /etc/motd args="['cheese=spam','spam=cheese']" ''' + path = os.path.expanduser(path) + # Largely inspired by Fabric's contrib.files.append() if 'args' in kwargs: @@ -1700,6 +1730,7 @@ def prepend(path, *args, **kwargs): salt '*' file.prepend /etc/motd args="['cheese=spam','spam=cheese']" ''' + path = os.path.expanduser(path) if 'args' in kwargs: if isinstance(kwargs['args'], list): @@ -1754,6 +1785,7 @@ def write(path, *args, **kwargs): salt '*' file.write /etc/motd args="['cheese=spam','spam=cheese']" ''' + path = os.path.expanduser(path) if 'args' in kwargs: if isinstance(kwargs['args'], list): @@ -1787,6 +1819,8 @@ def touch(name, atime=None, mtime=None): salt '*' file.touch /var/log/emptyfile ''' + name = os.path.expanduser(name) + if atime and atime.isdigit(): atime = int(atime) if mtime and mtime.isdigit(): @@ -1834,6 +1868,7 @@ def seek_read(path, size, offset): salt '*' file.seek_read /path/to/file 4096 0 ''' + path = os.path.expanduser(path) try: seek_fh = os.open(path, os.O_RDONLY) os.lseek(seek_fh, int(offset), 0) @@ -1864,6 +1899,7 @@ def seek_write(path, data, offset): salt '*' file.seek_write /path/to/file 'some data' 4096 ''' + path = os.path.expanduser(path) try: seek_fh = os.open(path, os.O_WRONLY) os.lseek(seek_fh, int(offset), 0) @@ -1892,6 +1928,7 @@ def truncate(path, length): salt '*' file.truncate /path/to/file 512 ''' + path = os.path.expanduser(path) try: seek_fh = open(path, 'r+') seek_fh.truncate(int(length)) @@ -1911,6 +1948,8 @@ def link(src, path): salt '*' file.link /path/to/file /path/to/link ''' + src = os.path.expanduser(src) + if not os.path.isabs(src): raise SaltInvocationError('File path must be absolute.') @@ -1937,7 +1976,7 @@ def is_link(path): # therefore helps API consistency by providing a single function to call for # both operating systems. - return os.path.islink(path) + return os.path.islink(os.path.expanduser(path)) def symlink(src, path): @@ -1950,6 +1989,8 @@ def symlink(src, path): salt '*' file.symlink /path/to/file /path/to/link ''' + src = os.path.expanduser(src) + if not os.path.isabs(src): raise SaltInvocationError('File path must be absolute.') @@ -1971,6 +2012,9 @@ def rename(src, dst): salt '*' file.rename /path/to/src /path/to/dst ''' + src = os.path.expanduser(src) + dst = os.path.expanduser(dst) + if not os.path.isabs(src): raise SaltInvocationError('File path must be absolute.') @@ -2004,6 +2048,9 @@ def copy(src, dst, recurse=False, remove_existing=False): salt '*' file.copy /path/to/src_dir /path/to/dst_dir recurse=True remove_existing=True ''' + src = os.path.expanduser(src) + dst = os.path.expanduser(dst) + if not os.path.isabs(src): raise SaltInvocationError('File path must be absolute.') @@ -2048,6 +2095,8 @@ def lstat(path): salt '*' file.lstat /path/to/file ''' + path = os.path.expanduser(path) + if not os.path.isabs(path): raise SaltInvocationError('Path to file must be absolute.') @@ -2080,6 +2129,8 @@ def access(path, mode): salt '*' file.access /path/to/file f salt '*' file.access /path/to/file x ''' + path = os.path.expanduser(path) + if not os.path.isabs(path): raise SaltInvocationError('Path to link must be absolute.') @@ -2108,6 +2159,8 @@ def readlink(path): salt '*' file.readlink /path/to/link ''' + path = os.path.expanduser(path) + if not os.path.isabs(path): raise SaltInvocationError('Path to link must be absolute.') @@ -2129,6 +2182,8 @@ def readdir(path): salt '*' file.readdir /path/to/dir/ ''' + path = os.path.expanduser(path) + if not os.path.isabs(path): raise SaltInvocationError('Dir path must be absolute.') @@ -2152,6 +2207,8 @@ def statvfs(path): salt '*' file.statvfs /path/to/file ''' + path = os.path.expanduser(path) + if not os.path.isabs(path): raise SaltInvocationError('File path must be absolute.') @@ -2175,6 +2232,8 @@ def stats(path, hash_type=None, follow_symlinks=True): salt '*' file.stats /etc/passwd ''' + path = os.path.expanduser(path) + ret = {} if not os.path.exists(path): try: @@ -2232,6 +2291,8 @@ def rmdir(path): salt '*' file.rmdir /tmp/foo/ ''' + path = os.path.expanduser(path) + if not os.path.isabs(path): raise SaltInvocationError('File path must be absolute.') @@ -2255,6 +2316,8 @@ def remove(path): salt '*' file.remove /tmp/foo ''' + path = os.path.expanduser(path) + if not os.path.isabs(path): raise SaltInvocationError('File path must be absolute.') @@ -2283,7 +2346,7 @@ def directory_exists(path): salt '*' file.directory_exists /etc ''' - return os.path.isdir(path) + return os.path.isdir(os.path.expanduser(path)) def file_exists(path): @@ -2297,7 +2360,7 @@ def file_exists(path): salt '*' file.file_exists /etc/passwd ''' - return os.path.isfile(path) + return os.path.isfile(os.path.expanduser(path)) def path_exists_glob(path): @@ -2315,7 +2378,7 @@ def path_exists_glob(path): salt '*' file.path_exists_glob /etc/pam*/pass* ''' - return True if glob.glob(path) else False + return True if glob.glob(os.path.expanduser(path)) else False def restorecon(path, recursive=False): @@ -2671,6 +2734,8 @@ def check_perms(name, ret, user, group, mode, follow_symlinks=False): .. versionchanged:: 2014.1.3 ``follow_symlinks`` option added ''' + name = os.path.expanduser(name) + if not ret: ret = {'name': name, 'changes': {}, @@ -2927,6 +2992,8 @@ def get_diff( salt '*' file.get_diff /home/fred/.vimrc salt://users/fred/.vimrc ''' + minionfile = os.path.expanduser(minionfile) + ret = '' if isinstance(env, salt._compat.string_types): @@ -3035,6 +3102,8 @@ def manage_file(name, ``follow_symlinks`` option added ''' + name = os.path.expanduser(name) + if not ret: ret = {'name': name, 'changes': {}, @@ -3333,6 +3402,8 @@ def mkdir(dir_path, salt '*' file.mkdir /opt/jetty/context ''' + dir_path = os.path.expanduser(dir_path) + directory = os.path.normpath(dir_path) if not os.path.isdir(directory): @@ -3363,6 +3434,8 @@ def makedirs_(path, salt '*' file.makedirs /opt/code/ ''' + path = os.path.expanduser(path) + # walk up the directory structure until we find the first existing # directory dirname = os.path.normpath(os.path.dirname(path)) @@ -3405,6 +3478,8 @@ def makedirs_perms(name, salt '*' file.makedirs_perms /opt/code ''' + name = os.path.expanduser(name) + path = os.path head, tail = path.split(name) if not tail: @@ -3436,6 +3511,8 @@ def get_devmm(name): salt '*' file.get_devmm /dev/chr ''' + name = os.path.expanduser(name) + if is_chrdev(name) or is_blkdev(name): stat_structure = os.stat(name) return ( @@ -3455,6 +3532,8 @@ def is_chrdev(name): salt '*' file.is_chrdev /dev/chr ''' + name = os.path.expanduser(name) + stat_structure = None try: stat_structure = os.stat(name) @@ -3484,6 +3563,8 @@ def mknod_chrdev(name, salt '*' file.mknod_chrdev /dev/chr 180 31 ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'comment': '', @@ -3526,6 +3607,8 @@ def is_blkdev(name): salt '*' file.is_blkdev /dev/blk ''' + name = os.path.expanduser(name) + stat_structure = None try: stat_structure = os.stat(name) @@ -3555,6 +3638,8 @@ def mknod_blkdev(name, salt '*' file.mknod_blkdev /dev/blk 8 999 ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'comment': '', @@ -3597,6 +3682,8 @@ def is_fifo(name): salt '*' file.is_fifo /dev/fifo ''' + name = os.path.expanduser(name) + stat_structure = None try: stat_structure = os.stat(name) @@ -3624,6 +3711,8 @@ def mknod_fifo(name, salt '*' file.mknod_fifo /dev/fifo ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'comment': '', @@ -3707,6 +3796,8 @@ def list_backups(path, limit=None): salt '*' file.list_backups /foo/bar/baz.txt ''' + path = os.path.expanduser(path) + try: limit = int(limit) except TypeError: @@ -3766,6 +3857,8 @@ def restore_backup(path, backup_id): salt '*' file.restore_backup /foo/bar/baz.txt 0 ''' + path = os.path.expanduser(path) + # Note: This only supports minion backups, so this function will need to be # modified if/when master backups are implemented. ret = {'result': False, @@ -3825,6 +3918,8 @@ def delete_backup(path, backup_id): salt '*' file.restore_backup /foo/bar/baz.txt 0 ''' + path = os.path.expanduser(path) + ret = {'result': False, 'comment': 'Invalid backup_id \'{0}\''.format(backup_id)} try: @@ -3883,6 +3978,8 @@ def grep(path, salt '*' file.grep /etc/sysconfig/network-scripts/ifcfg-eth0 ipaddr " -i -B2" salt '*' file.grep "/etc/sysconfig/network-scripts/*" ipaddr " -i -l" ''' + path = os.path.expanduser(path) + if args: options = ' '.join(args) else: diff --git a/salt/states/file.py b/salt/states/file.py index 569f801238..e4483a52bd 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -725,6 +725,8 @@ def symlink( The permissions to set on this file, aka 644, 0775, 4664. Not supported on Windows ''' + name = os.path.expanduser(name) + # Make sure that leading zeros stripped by YAML loader are added back mode = __salt__['config.manage_mode'](mode) @@ -881,6 +883,8 @@ def absent(name): name The path which should be deleted ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'result': True, @@ -931,6 +935,8 @@ def exists(name): name Absolute path which must exist ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'result': True, @@ -950,6 +956,8 @@ def missing(name): name Absolute path which must NOT exist ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'result': True, @@ -1219,6 +1227,8 @@ def managed(name, Do run the state only if the check_cmd succeeds ''' + name = os.path.expanduser(name) + # Make sure that leading zeros stripped by YAML loader are added back mode = __salt__['config.manage_mode'](mode) @@ -1573,6 +1583,7 @@ def directory(name, .. versionadded:: 2014.7.0 ''' + name = os.path.expanduser(name) # Remove trailing slash, if present if name[-1] == '/': name = name[:-1] @@ -1910,6 +1921,8 @@ def recurse(name, recursively removed so that symlink creation can proceed. This option is usually not needed except in special circumstances. ''' + name = os.path.expanduser(name) + user = _test_owner(kwargs, user=user) if salt.utils.is_windows(): if group is not None: @@ -2277,6 +2290,8 @@ def replace(name, Params are identical to :py:func:`~salt.modules.file.replace`. ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''} check_res, check_msg = _check_file(name) @@ -2398,6 +2413,8 @@ def blockreplace( text 4 # END managed zone 42 -- ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''} check_res, check_msg = _check_file(name) @@ -2508,6 +2525,8 @@ def sed(name, .. versionadded:: 0.9.5 ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''} check_res, check_msg = _check_file(name) @@ -2613,6 +2632,8 @@ def comment(name, regex, char='#', backup='.bak'): .. versionadded:: 0.9.5 ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''} check_res, check_msg = _check_file(name) @@ -2693,6 +2714,8 @@ def uncomment(name, regex, char='#', backup='.bak'): .. versionadded:: 0.9.5 ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''} check_res, check_msg = _check_file(name) @@ -2896,6 +2919,8 @@ def append(name, .. versionadded:: 0.9.5 ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''} if sources is None: @@ -3075,6 +3100,8 @@ def prepend(name, .. versionadded:: 2014.7.0 ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''} if sources is None: @@ -3240,6 +3267,8 @@ def patch(name, - source: salt://file.patch - hash: md5=e138491e9d5b97023cea823fe17bac22 ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''} check_res, check_msg = _check_file(name) if not check_res: @@ -3335,6 +3364,8 @@ def touch(name, atime=None, mtime=None, makedirs=False): .. versionadded:: 0.9.5 ''' + name = os.path.expanduser(name) + ret = { 'name': name, 'changes': {}, @@ -3390,6 +3421,9 @@ def copy(name, source, force=False, makedirs=False): If the target subdirectories don't exist create them ''' + name = os.path.expanduser(name) + source = os.path.expanduser(source) + ret = { 'name': name, 'changes': {}, @@ -3484,6 +3518,9 @@ def rename(name, source, force=False, makedirs=False): If the target subdirectories don't exist create them ''' + name = os.path.expanduser(name) + source = os.path.expanduser(source) + ret = { 'name': name, 'changes': {}, @@ -3780,6 +3817,7 @@ def serialize(name, "name": "naive" } ''' + name = os.path.expanduser(name) ret = {'changes': {}, 'comment': '', @@ -3941,6 +3979,8 @@ def mknod(name, ntype, major=0, minor=0, user=None, group=None, mode='0600'): .. versionadded:: 0.17.0 ''' + name = os.path.expanduser(name) + ret = {'name': name, 'changes': {}, 'comment': '',