mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-05-20 10:34:30 +00:00
snapshot: Fix snapshots filling up the disk
- Snapper's cleanup algorithms don't apply limits unless they are specified in the form of ranges. Changed all limit values in the configuration to ranges. - Also, all MIN_AGE values have been set to 0 to avoid the disk space filling up in case of a large number of snapshots generated in a very short amount of time. - FREE_LIMIT has been increased to 30% from the default 20% since backup archives also take up disk space on the root partition. Fixes #1435 Signed-off-by: Joseph Nuthalapati <njoseph@thoughtworks.com> Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
parent
8dbf73d3f5
commit
8ba0bda869
@ -39,6 +39,9 @@ def parse_arguments():
|
|||||||
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
|
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
|
||||||
|
|
||||||
subparsers.add_parser('setup', help='Configure snapper')
|
subparsers.add_parser('setup', help='Configure snapper')
|
||||||
|
subparsers.add_parser(
|
||||||
|
'migrate',
|
||||||
|
help='Migrate existing user configuration to the new format')
|
||||||
subparsers.add_parser('list', help='List snapshots')
|
subparsers.add_parser('list', help='List snapshots')
|
||||||
subparsers.add_parser('create', help='Create snapshot')
|
subparsers.add_parser('create', help='Create snapshot')
|
||||||
subparsers.add_parser('get-config', help='Configurations of snapshot')
|
subparsers.add_parser('get-config', help='Configurations of snapshot')
|
||||||
@ -85,11 +88,20 @@ def subcommand_setup(_):
|
|||||||
|
|
||||||
def _set_default_config():
|
def _set_default_config():
|
||||||
command = [
|
command = [
|
||||||
'snapper', 'set-config', 'TIMELINE_CREATE=yes',
|
'snapper',
|
||||||
'TIMELINE_LIMIT_HOURLY=10', 'TIMELINE_LIMIT_MONTHLY=2',
|
'set-config',
|
||||||
'TIMELINE_LIMIT_WEEKLY=2', 'TIMELINE_LIMIT_YEARLY=0',
|
'TIMELINE_CREATE=yes',
|
||||||
'TIMELINE_LIMIT_DAILY=3', 'NUMBER_MIN_AGE=1296000', 'NUMBER_LIMIT=0',
|
'TIMELINE_MIN_AGE=0',
|
||||||
'NUMBER_LIMIT_IMPORTANT=4-10'
|
'TIMELINE_LIMIT_HOURLY=0-10',
|
||||||
|
'TIMELINE_LIMIT_DAILY=0-3',
|
||||||
|
'TIMELINE_LIMIT_WEEKLY=0-2',
|
||||||
|
'TIMELINE_LIMIT_MONTHLY=0-2',
|
||||||
|
'TIMELINE_LIMIT_YEARLY=0-0',
|
||||||
|
'NUMBER_MIN_AGE=0',
|
||||||
|
'NUMBER_LIMIT=0-100',
|
||||||
|
'NUMBER_LIMIT_IMPORTANT=0-20',
|
||||||
|
'EMPTY_PRE_POST_MIN_AGE=0',
|
||||||
|
'FREE_LIMIT=0.3',
|
||||||
]
|
]
|
||||||
subprocess.run(command, check=True)
|
subprocess.run(command, check=True)
|
||||||
|
|
||||||
@ -223,7 +235,7 @@ def subcommand_set_config(arguments):
|
|||||||
subprocess.run(command, check=True)
|
subprocess.run(command, check=True)
|
||||||
|
|
||||||
|
|
||||||
def subcommand_get_config(_):
|
def _get_config():
|
||||||
command = ['snapper', 'get-config']
|
command = ['snapper', 'get-config']
|
||||||
process = subprocess.run(command, stdout=subprocess.PIPE, check=True)
|
process = subprocess.run(command, stdout=subprocess.PIPE, check=True)
|
||||||
lines = process.stdout.decode().splitlines()
|
lines = process.stdout.decode().splitlines()
|
||||||
@ -231,9 +243,45 @@ def subcommand_get_config(_):
|
|||||||
for line in lines[2:]:
|
for line in lines[2:]:
|
||||||
parts = [part.strip() for part in line.split('|')]
|
parts = [part.strip() for part in line.split('|')]
|
||||||
config[parts[0]] = parts[1]
|
config[parts[0]] = parts[1]
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def subcommand_get_config(_):
|
||||||
|
config = _get_config()
|
||||||
print(json.dumps(config))
|
print(json.dumps(config))
|
||||||
|
|
||||||
|
|
||||||
|
def subcommand_migrate(_):
|
||||||
|
"""Migrate existing user configuration for snapshots
|
||||||
|
to the new configuration format.
|
||||||
|
Add in version 4 of the snapshots module.
|
||||||
|
This command will not check or perform first setup steps.
|
||||||
|
"""
|
||||||
|
config = _get_config()
|
||||||
|
|
||||||
|
def convert_to_range(key):
|
||||||
|
value = config[key]
|
||||||
|
value = value if '-' in value else '0-{}'.format(value)
|
||||||
|
return '{}={}'.format(key, value)
|
||||||
|
|
||||||
|
command = [
|
||||||
|
'snapper',
|
||||||
|
'set-config',
|
||||||
|
'TIMELINE_MIN_AGE=0',
|
||||||
|
convert_to_range('TIMELINE_LIMIT_HOURLY'),
|
||||||
|
convert_to_range('TIMELINE_LIMIT_DAILY'),
|
||||||
|
convert_to_range('TIMELINE_LIMIT_WEEKLY'),
|
||||||
|
convert_to_range('TIMELINE_LIMIT_MONTHLY'),
|
||||||
|
convert_to_range('TIMELINE_LIMIT_YEARLY'),
|
||||||
|
'NUMBER_MIN_AGE=0',
|
||||||
|
'NUMBER_LIMIT=0-100',
|
||||||
|
'NUMBER_LIMIT_IMPORTANT=0-20',
|
||||||
|
'EMPTY_PRE_POST_MIN_AGE=0',
|
||||||
|
'FREE_LIMIT=0.3',
|
||||||
|
]
|
||||||
|
subprocess.run(command, check=True)
|
||||||
|
|
||||||
|
|
||||||
def subcommand_kill_daemon(_):
|
def subcommand_kill_daemon(_):
|
||||||
"""Kill the snapper daemon.
|
"""Kill the snapper daemon.
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@ from plinth.menu import main_menu
|
|||||||
|
|
||||||
from .manifest import backup
|
from .manifest import backup
|
||||||
|
|
||||||
version = 3
|
version = 4
|
||||||
|
|
||||||
managed_packages = ['snapper']
|
managed_packages = ['snapper']
|
||||||
|
|
||||||
@ -67,13 +67,16 @@ def init():
|
|||||||
def setup(helper, old_version=None):
|
def setup(helper, old_version=None):
|
||||||
"""Install and configure the module."""
|
"""Install and configure the module."""
|
||||||
helper.install(managed_packages)
|
helper.install(managed_packages)
|
||||||
|
if old_version:
|
||||||
|
helper.call('post', actions.superuser_run, 'snapshot', ['migrate'])
|
||||||
|
else:
|
||||||
helper.call('post', actions.superuser_run, 'snapshot', ['setup'])
|
helper.call('post', actions.superuser_run, 'snapshot', ['setup'])
|
||||||
|
|
||||||
|
|
||||||
def load_augeas():
|
def load_augeas():
|
||||||
"""Initialize Augeas."""
|
"""Initialize Augeas."""
|
||||||
aug = augeas.Augeas(
|
aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
|
||||||
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD)
|
augeas.Augeas.NO_MODL_AUTOLOAD)
|
||||||
|
|
||||||
# shell-script config file lens
|
# shell-script config file lens
|
||||||
aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')
|
aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')
|
||||||
@ -96,21 +99,24 @@ def get_configuration():
|
|||||||
def get_boolean_choice(status):
|
def get_boolean_choice(status):
|
||||||
return ('yes', 'Enabled') if status else ('no', 'Disabled')
|
return ('yes', 'Enabled') if status else ('no', 'Disabled')
|
||||||
|
|
||||||
|
def get_max_from_range(key):
|
||||||
|
return output[key].split('-')[-1]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'enable_timeline_snapshots':
|
'enable_timeline_snapshots':
|
||||||
get_boolean_choice(output['TIMELINE_CREATE'] == 'yes'),
|
get_boolean_choice(output['TIMELINE_CREATE'] == 'yes'),
|
||||||
'enable_software_snapshots':
|
'enable_software_snapshots':
|
||||||
get_boolean_choice(is_apt_snapshots_enabled(aug)),
|
get_boolean_choice(is_apt_snapshots_enabled(aug)),
|
||||||
'hourly_limit':
|
'hourly_limit':
|
||||||
output['TIMELINE_LIMIT_HOURLY'],
|
get_max_from_range('TIMELINE_LIMIT_HOURLY'),
|
||||||
'daily_limit':
|
'daily_limit':
|
||||||
output['TIMELINE_LIMIT_DAILY'],
|
get_max_from_range('TIMELINE_LIMIT_DAILY'),
|
||||||
'weekly_limit':
|
'weekly_limit':
|
||||||
output['TIMELINE_LIMIT_WEEKLY'],
|
get_max_from_range('TIMELINE_LIMIT_WEEKLY'),
|
||||||
'yearly_limit':
|
|
||||||
output['TIMELINE_LIMIT_YEARLY'],
|
|
||||||
'monthly_limit':
|
'monthly_limit':
|
||||||
output['TIMELINE_LIMIT_MONTHLY'],
|
get_max_from_range('TIMELINE_LIMIT_MONTHLY'),
|
||||||
|
'yearly_limit':
|
||||||
|
get_max_from_range('TIMELINE_LIMIT_YEARLY'),
|
||||||
'number_min_age':
|
'number_min_age':
|
||||||
round(int(output['NUMBER_MIN_AGE']) / 86400),
|
round(int(output['NUMBER_MIN_AGE']) / 86400),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -98,13 +98,17 @@ def update_configuration(request, old_status, new_status):
|
|||||||
def make_config(args):
|
def make_config(args):
|
||||||
key, stamp = args[0], args[1]
|
key, stamp = args[0], args[1]
|
||||||
if old_status[key] != new_status[key]:
|
if old_status[key] != new_status[key]:
|
||||||
|
if 'limit' in key:
|
||||||
|
return stamp.format('0-{}'.format(new_status[key]))
|
||||||
|
else:
|
||||||
return stamp.format(new_status[key])
|
return stamp.format(new_status[key])
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
new_status['number_min_age'] = int(new_status['number_min_age']) * 86400
|
new_status['number_min_age'] = int(new_status['number_min_age']) * 86400
|
||||||
|
|
||||||
config = filter(None,
|
config = filter(
|
||||||
|
None,
|
||||||
map(make_config, [
|
map(make_config, [
|
||||||
('enable_timeline_snapshots', 'TIMELINE_CREATE={}'),
|
('enable_timeline_snapshots', 'TIMELINE_CREATE={}'),
|
||||||
('hourly_limit', 'TIMELINE_LIMIT_HOURLY={}'),
|
('hourly_limit', 'TIMELINE_LIMIT_HOURLY={}'),
|
||||||
@ -115,8 +119,7 @@ def update_configuration(request, old_status, new_status):
|
|||||||
('number_min_age', 'NUMBER_MIN_AGE={}'),
|
('number_min_age', 'NUMBER_MIN_AGE={}'),
|
||||||
]))
|
]))
|
||||||
|
|
||||||
if old_status['enable_software_snapshots'] != new_status[
|
if old_status['enable_software_snapshots'] != new_status['enable_software_snapshots']:
|
||||||
'enable_software_snapshots']:
|
|
||||||
if new_status['enable_software_snapshots'] == 'yes':
|
if new_status['enable_software_snapshots'] == 'yes':
|
||||||
actions.superuser_run('snapshot', ['disable-apt-snapshot', 'no'])
|
actions.superuser_run('snapshot', ['disable-apt-snapshot', 'no'])
|
||||||
else:
|
else:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user