Skip to content

Commit bae7a05

Browse files
committed
Merge pull request #11: Add --use-rmdir option
2 parents e3ff1ce + bbc0df3 commit bae7a05

File tree

3 files changed

+42
-12
lines changed

3 files changed

+42
-12
lines changed

README.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ intended you have no right to complain ;-).
211211
remote system over SSH)."
212212
"``-n``, ``--dry-run``","Don't make any changes, just print what would be done. This makes it easy
213213
to evaluate the impact of a rotation scheme without losing any backups."
214+
"``-D``, ``--use-rmdir``","Use ""rmdir"" to remove the backups (useful with CephFS snapshots for example)."
214215
"``-v``, ``--verbose``",Increase logging verbosity (can be repeated).
215216
"``-q``, ``--quiet``",Decrease logging verbosity (can be repeated).
216217
"``-h``, ``--help``",Show this message and exit.
@@ -359,8 +360,8 @@ Supported configuration options
359360
- If an include or exclude list is defined in the configuration file it
360361
overrides the include or exclude list given on the command line.
361362

362-
- The ``prefer-recent``, ``strict`` and ``use-sudo`` options expect a boolean
363-
value (``yes``, ``no``, ``true``, ``false``, ``1`` or ``0``).
363+
- The ``prefer-recent``, ``strict``, ``rmdir`` and ``use-sudo`` options expect a
364+
boolean value (``yes``, ``no``, ``true``, ``false``, ``1`` or ``0``).
364365

365366
- The ``ionice`` option expects one of the I/O scheduling class names ``idle``,
366367
``best-effort`` or ``realtime``.

rotate_backups/__init__.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ def load_config_file(configuration_file=None, expand=True):
197197
exclude_list=split(items.get('exclude-list', '')),
198198
io_scheduling_class=items.get('ionice'),
199199
strict=coerce_boolean(items.get('strict', 'yes')),
200-
prefer_recent=coerce_boolean(items.get('prefer-recent', 'no')))
200+
prefer_recent=coerce_boolean(items.get('prefer-recent', 'no')),
201+
rmdir=items.get('use-rmdir'))
201202
# Expand filename patterns?
202203
if expand and location.have_wildcards:
203204
logger.verbose("Expanding filename pattern %s on %s ..", location.directory, location.context)
@@ -241,8 +242,9 @@ def __init__(self, rotation_scheme, **options):
241242
:param rotation_scheme: Used to set :attr:`rotation_scheme`.
242243
:param options: Any keyword arguments are used to set the values of the
243244
properties :attr:`config_file`, :attr:`dry_run`,
244-
:attr:`exclude_list`, :attr:`include_list`,
245-
:attr:`io_scheduling_class` and :attr:`strict`.
245+
:attr:`rmdir`, :attr:`exclude_list`,
246+
:attr:`include_list`, :attr:`io_scheduling_class` and
247+
:attr:`strict`.
246248
"""
247249
options.update(rotation_scheme=rotation_scheme)
248250
super(RotateBackups, self).__init__(**options)
@@ -269,6 +271,18 @@ def dry_run(self):
269271
"""
270272
return False
271273

274+
@mutable_property
275+
def rmdir(self):
276+
"""
277+
:data:`True` to use `rmdir` to remove the snapshots, :data:`False` to use `rm -r` (defaults to :data:`False`).
278+
279+
Normally the backups are removed one file at a file using the command `rm -r`.
280+
Some file-systems are capable of removing a whole directory with the command `rmdir`,
281+
even when the directory is not empty. For example, this is how CephFS snapshots are
282+
removed.
283+
"""
284+
return False
285+
272286
@cached_property(writable=True)
273287
def exclude_list(self):
274288
"""
@@ -467,11 +481,18 @@ class together to implement backup rotation with an easy to use Python
467481
else:
468482
logger.info("Deleting %s ..", friendly_name)
469483
if not self.dry_run:
470-
command = location.context.prepare(
471-
'rm', '-Rf', backup.pathname,
472-
group_by=(location.ssh_alias, location.mount_point),
473-
ionice=self.io_scheduling_class,
474-
)
484+
if not self.rmdir:
485+
command = location.context.prepare(
486+
'rm', '-Rf', backup.pathname,
487+
group_by=(location.ssh_alias, location.mount_point),
488+
ionice=self.io_scheduling_class,
489+
)
490+
else:
491+
command = location.context.prepare(
492+
'rmdir', backup.pathname,
493+
group_by=(location.ssh_alias, location.mount_point),
494+
ionice=self.io_scheduling_class,
495+
)
475496
rotation_commands.append(command)
476497
if not prepare:
477498
timer = Timer()

rotate_backups/cli.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@
154154
Don't make any changes, just print what would be done. This makes it easy
155155
to evaluate the impact of a rotation scheme without losing any backups.
156156
157+
-D, --use-rmdir
158+
159+
Remove backups by calling `rmdir' to directly remove the whole directory
160+
instead of deleting each of the files in it. This works only with special
161+
directories such as CephFS snapshot.
162+
157163
-v, --verbose
158164
159165
Increase logging verbosity (can be repeated).
@@ -202,10 +208,10 @@ def main():
202208
selected_locations = []
203209
# Parse the command line arguments.
204210
try:
205-
options, arguments = getopt.getopt(sys.argv[1:], 'M:H:d:w:m:y:I:x:jpri:c:r:unvqh', [
211+
options, arguments = getopt.getopt(sys.argv[1:], 'M:H:d:w:m:y:I:x:jpri:c:r:uDnvqh', [
206212
'minutely=', 'hourly=', 'daily=', 'weekly=', 'monthly=', 'yearly=',
207213
'include=', 'exclude=', 'parallel', 'prefer-recent', 'relaxed',
208-
'ionice=', 'config=', 'use-sudo', 'dry-run', 'verbose', 'quiet',
214+
'ionice=', 'config=', 'use-sudo', 'dry-run', 'use-rmdir', 'verbose', 'quiet',
209215
'help',
210216
])
211217
for option, value in options:
@@ -241,6 +247,8 @@ def main():
241247
elif option in ('-n', '--dry-run'):
242248
logger.info("Performing a dry run (because of %s option) ..", option)
243249
kw['dry_run'] = True
250+
elif option in ('-D', '--use-rmdir'):
251+
kw['rmdir'] = True
244252
elif option in ('-v', '--verbose'):
245253
coloredlogs.increase_verbosity()
246254
elif option in ('-q', '--quiet'):

0 commit comments

Comments
 (0)