Symlink support in file.recurse

This commit is contained in:
Mickey Malone 2013-09-24 21:29:52 -05:00
parent e4b794aab3
commit 8025c47ae3
2 changed files with 68 additions and 4 deletions

View File

@ -242,15 +242,22 @@ def symlink_list(load):
ret = {}
if load['env'] not in __opts__['file_roots']:
return ret
for path in __opts__['file_roots'][load['env']]:
try:
prefix = load['prefix'].strip('/')
except KeyError:
prefix = ''
# No need to follow symlinks here, this is a symlink hunt :-)
# If a user has symlinked dirs that contain other symlinks, then setting
# the __opts__['fileserver_followsymlinks'] to False will not be desired
# unless the user has only 1 deep symlink recursion in the roots.
# This causes os.walk to stop at the first symlink encounter.
# It is the responsibility of the user to ensure that os.walk does not
# encounter an infinite symlink recursion. Python docs warn about this in
# the os.walk documentation if followlinks=True. If infinite symlink
# is encountered, then the recursion will be passed to the Minion leading
# to undesired results.
for root, dirs, files in os.walk(os.path.join(path, prefix),
followlinks=False):
followlinks=__opts__['fileserver_followsymlinks']):
for fname in files:
if not os.path.islink(os.path.join(root, fname)):
continue
@ -262,5 +269,8 @@ def symlink_list(load):
ret[rel_fn] = os.readlink(os.path.join(root, fname))
for dname in dirs:
if os.path.islink(os.path.join(root, dname)):
ret[dname] = os.readlink(os.path.join(root, dname))
ret[os.path.relpath(os.path.join(root,
dname),
path)] = os.readlink(os.path.join(root,
dname))
return ret

View File

@ -1340,6 +1340,7 @@ def recurse(name,
group=None,
dir_mode=None,
file_mode=None,
sym_mode=None,
template=None,
context=None,
defaults=None,
@ -1349,6 +1350,7 @@ def recurse(name,
include_pat=None,
exclude_pat=None,
maxdepth=None,
keep_symlinks=False,
**kwargs):
'''
Recurse through a subdirectory on the master and copy said subdirectory
@ -1385,6 +1387,9 @@ def recurse(name,
file_mode
The permissions mode to set any files created
sym_mode
the permissions mode to set on any symlink created
template
If this setting is applied then the named templating engine will be
used to render the downloaded file, currently jinja, mako, and wempy
@ -1434,6 +1439,10 @@ def recurse(name,
directory
- maxdepth: 1 :: Only include files located in the source
or immediate subdirectories
keep_symlinks
Keep symlinks when copying from the source. Set this to True if
keeping symlinks intact is desired.
'''
user = _test_owner(kwargs, user=user)
ret = {'name': name,
@ -1581,10 +1590,20 @@ def recurse(name,
#we're searching for things that start with this *directory*.
# use '/' since #master only runs on POSIX
srcpath = srcpath + '/'
# If we are instructed to keep symlinks, then grab the dict of links
if keep_symlinks:
symlinks = __salt__['cp.list_master_symlinks'](env, srcpath)
for fn_ in __salt__['cp.list_master'](env, srcpath):
if not fn_.strip():
continue
# Check for symlinked files if symlinks are on the table.
# Symlinks will be processed after the entire dir/file structure
# is created.
if keep_symlinks and symlinks.get(fn_):
log.debug('** skipping file ** {0}, it is destined for a symlink'.format(fn_))
continue
# fn_ here is the absolute (from file_roots) source path of
# the file to copy from; it is either a normal file or an
# empty dir(if include_empty==true).
@ -1613,6 +1632,15 @@ def recurse(name,
keep.add(dest)
if dirname not in vdir:
# Check for symlinked dirs if symlinks are on the table.
# Symlinks will be processed after the entire dir/file structure
# is created.
_dir = relname.split('/')
_dir.pop()
_dir = os.path.join(srcpath,'/'.join(_dir))
if keep_symlinks and symlinks.get(_dir):
log.debug('** skipping dir ** {0}, it is destined for a symlink'.format(_dir))
continue
# verify the directory perms if they are set
manage_directory(dirname)
vdir.add(dirname)
@ -1628,9 +1656,35 @@ def recurse(name,
exclude_pat):
continue
mdest = os.path.join(name, os.path.relpath(mdir, srcpath))
# Check for symlinks that happen to point to an empty dir.
# This will be processed along with the other symlinks.
if keep_symlinks and symlinks.get(mdir):
log.debug('** skipping empty dir ** {0}, it is destined for a symlink'.format(mdir))
continue
manage_directory(mdest)
keep.add(mdest)
if keep_symlinks:
for lname, ltarget in symlinks.items():
if not _check_include_exclude(os.path.relpath(lname, srcpath),
include_pat,
exclude_pat):
continue
srelpath = os.path.relpath(lname, srcpath)
# Force the symlink and makedirs.
# This addresses any symlink dependencies
# and funky symlink recursion that we may encounter.
_ret = symlink(os.path.join(name, srelpath),
ltarget,
force=True,
makedirs=True,
user=user,
group=group,
mode=sym_mode)
if not _ret:
continue
merge_ret(os.path.join(name,srelpath),_ret)
keep = list(keep)
if clean:
# TODO: Use directory(clean=True) instead