mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #35605 from rallytime/bp-32739
Back-port #32739 to 2016.3
This commit is contained in:
commit
4153aeba29
3 changed files with 64 additions and 29 deletions
|
@ -20,7 +20,7 @@ from salt.exceptions import CommandExecutionError, SaltInvocationError
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _check(delete, force, update, passwordfile, exclude, excludefrom):
|
||||
def _check(delete, force, update, passwordfile, exclude, excludefrom, dryrun):
|
||||
'''
|
||||
Generate rsync options
|
||||
'''
|
||||
|
@ -40,6 +40,8 @@ def _check(delete, force, update, passwordfile, exclude, excludefrom):
|
|||
exclude = False
|
||||
if exclude:
|
||||
options.extend(['--exclude', exclude])
|
||||
if dryrun:
|
||||
options.append('--dry-run')
|
||||
return options
|
||||
|
||||
|
||||
|
@ -50,7 +52,8 @@ def rsync(src,
|
|||
update=False,
|
||||
passwordfile=None,
|
||||
exclude=None,
|
||||
excludefrom=None):
|
||||
excludefrom=None,
|
||||
dryrun=False):
|
||||
'''
|
||||
.. versionchanged:: 2016.3.0
|
||||
Return data now contains just the output of the rsync command, instead
|
||||
|
@ -82,13 +85,16 @@ def rsync(src,
|
|||
exclude = __salt__['config.option']('rsync.exclude')
|
||||
if not excludefrom:
|
||||
excludefrom = __salt__['config.option']('rsync.excludefrom')
|
||||
if not dryrun:
|
||||
dryrun = __salt__['config.option']('rsync.dryrun')
|
||||
if not src or not dst:
|
||||
raise SaltInvocationError('src and dst cannot be empty')
|
||||
|
||||
option = _check(delete, force, update, passwordfile, exclude, excludefrom)
|
||||
option = _check(delete, force, update, passwordfile, exclude, excludefrom, dryrun)
|
||||
cmd = ['rsync'] + option + [src, dst]
|
||||
log.debug('Running rsync command: {0}'.format(cmd))
|
||||
try:
|
||||
return __salt__['cmd.run'](cmd, python_shell=False)
|
||||
return __salt__['cmd.run_all'](cmd, python_shell=False)
|
||||
except (IOError, OSError) as exc:
|
||||
raise CommandExecutionError(exc.strerror)
|
||||
|
||||
|
|
|
@ -14,9 +14,17 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
'''
|
||||
Rsync state.
|
||||
State to synchronize files and directories with rsync.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
/opt/user-backups:
|
||||
rsync.synchronized:
|
||||
- source: /home
|
||||
- force: True
|
||||
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
@ -36,9 +44,6 @@ def __virtual__():
|
|||
def _get_summary(rsync_out):
|
||||
'''
|
||||
Get summary from the rsync successfull output.
|
||||
|
||||
:param rsync_out:
|
||||
:return:
|
||||
'''
|
||||
|
||||
return "- " + "\n- ".join([elm for elm in rsync_out.split("\n\n")[-1].replace(" ", "\n").split("\n") if elm])
|
||||
|
@ -47,9 +52,6 @@ def _get_summary(rsync_out):
|
|||
def _get_changes(rsync_out):
|
||||
'''
|
||||
Get changes from the rsync successfull output.
|
||||
|
||||
:param rsync_out:
|
||||
:return:
|
||||
'''
|
||||
copied = list()
|
||||
deleted = list()
|
||||
|
@ -73,28 +75,45 @@ def synchronized(name, source,
|
|||
passwordfile=None,
|
||||
exclude=None,
|
||||
excludefrom=None,
|
||||
prepare=False):
|
||||
prepare=False,
|
||||
dryrun=False):
|
||||
'''
|
||||
Guarantees that the source directory is always copied to the target.
|
||||
|
||||
:param name: Name of the target directory.
|
||||
:param source: Source directory.
|
||||
:param prepare: Create destination directory if it does not exists.
|
||||
:param delete: Delete extraneous files from the destination dirs (True or False)
|
||||
:param force: Force deletion of dirs even if not empty
|
||||
:param update: Skip files that are newer on the receiver (True or False)
|
||||
:param passwordfile: Read daemon-access password from the file (path)
|
||||
:param exclude: Exclude files, that matches pattern.
|
||||
:param excludefrom: Read exclude patterns from the file (path)
|
||||
:return:
|
||||
name
|
||||
Name of the target directory.
|
||||
|
||||
.. code-block:: yaml
|
||||
source
|
||||
Source directory.
|
||||
|
||||
/opt/user-backups:
|
||||
rsync.synchronized:
|
||||
- source: /home
|
||||
- force: True
|
||||
prepare
|
||||
Create destination directory if it does not exists.
|
||||
|
||||
delete
|
||||
Delete extraneous files from the destination dirs (True or False)
|
||||
|
||||
force
|
||||
Force deletion of dirs even if not empty
|
||||
|
||||
update
|
||||
Skip files that are newer on the receiver (True or False)
|
||||
|
||||
passwordfile
|
||||
Read daemon-access password from the file (path)
|
||||
|
||||
exclude
|
||||
Exclude files, that matches pattern.
|
||||
|
||||
excludefrom
|
||||
Read exclude patterns from the file (path)
|
||||
|
||||
dryrun
|
||||
Perform a trial run with no changes made. Is the same as
|
||||
doing test=True
|
||||
|
||||
.. versionadded:: 2016.3.1
|
||||
'''
|
||||
|
||||
ret = {'name': name, 'changes': {}, 'result': True, 'comment': ''}
|
||||
|
||||
if not os.path.exists(source):
|
||||
|
@ -107,8 +126,18 @@ def synchronized(name, source,
|
|||
if not os.path.exists(name) and prepare:
|
||||
os.makedirs(name)
|
||||
|
||||
if __opts__['test']:
|
||||
dryrun = True
|
||||
|
||||
result = __salt__['rsync.rsync'](source, name, delete=delete, force=force, update=update,
|
||||
passwordfile=passwordfile, exclude=exclude, excludefrom=excludefrom)
|
||||
passwordfile=passwordfile, exclude=exclude, excludefrom=excludefrom,
|
||||
dryrun=dryrun)
|
||||
|
||||
if __opts__['test'] or dryrun:
|
||||
ret['result'] = None
|
||||
ret['comment'] = _get_summary(result['stdout'])
|
||||
return ret
|
||||
|
||||
if result.get('retcode'):
|
||||
ret['result'] = False
|
||||
ret['comment'] = result['stderr']
|
||||
|
|
|
@ -40,7 +40,7 @@ class RsyncTestCase(TestCase):
|
|||
|
||||
with patch.dict(rsync.__salt__,
|
||||
{'config.option': MagicMock(return_value='A'),
|
||||
'cmd.run': MagicMock(side_effect=[IOError('f'),
|
||||
'cmd.run_all': MagicMock(side_effect=[IOError('f'),
|
||||
'A'])}):
|
||||
with patch.object(rsync, '_check', return_value=['A']):
|
||||
self.assertRaises(CommandExecutionError, rsync.rsync, 'a', 'b')
|
||||
|
|
Loading…
Add table
Reference in a new issue