123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- import logging
- import os
- import requests
- from borgmatic import execute
- logger = logging.getLogger(__name__)
- def interpolate_context(command, context):
- '''
- Given a single hook command and a dict of context names/values, interpolate the values by
- "{name}" into the command and return the result.
- '''
- for name, value in context.items():
- command = command.replace('{%s}' % name, str(value))
- return command
- def execute_hook(commands, umask, config_filename, description, dry_run, **context):
- '''
- Given a list of hook commands to execute, a umask to execute with (or None), a config filename,
- a hook description, and whether this is a dry run, run the given commands. Or, don't run them
- if this is a dry run.
- The context contains optional values interpolated by name into the hook commands. Currently,
- this only applies to the on_error hook.
- Raise ValueError if the umask cannot be parsed.
- Raise subprocesses.CalledProcessError if an error occurs in a hook.
- '''
- if not commands:
- logger.debug('{}: No commands to run for {} hook'.format(config_filename, description))
- return
- dry_run_label = ' (dry run; not actually running hooks)' if dry_run else ''
- context['configuration_filename'] = config_filename
- commands = [interpolate_context(command, context) for command in commands]
- if len(commands) == 1:
- logger.info(
- '{}: Running command for {} hook{}'.format(config_filename, description, dry_run_label)
- )
- else:
- logger.info(
- '{}: Running {} commands for {} hook{}'.format(
- config_filename, len(commands), description, dry_run_label
- )
- )
- if umask:
- parsed_umask = int(str(umask), 8)
- logger.debug('{}: Set hook umask to {}'.format(config_filename, oct(parsed_umask)))
- original_umask = os.umask(parsed_umask)
- else:
- original_umask = None
- try:
- for command in commands:
- if not dry_run:
- execute.execute_command(
- [command],
- output_log_level=logging.ERROR
- if description == 'on-error'
- else logging.WARNING,
- shell=True,
- )
- finally:
- if original_umask:
- os.umask(original_umask)
- def ping_healthchecks(ping_url_or_uuid, config_filename, dry_run, append=None):
- '''
- Ping the given healthchecks.io URL or UUID, appending the append string if any. Use the given
- configuration filename in any log entries. If this is a dry run, then don't actually ping
- anything.
- '''
- if not ping_url_or_uuid:
- logger.debug('{}: No healthchecks hook set'.format(config_filename))
- return
- ping_url = (
- ping_url_or_uuid
- if ping_url_or_uuid.startswith('http')
- else 'https://hc-ping.com/{}'.format(ping_url_or_uuid)
- )
- dry_run_label = ' (dry run; not actually pinging)' if dry_run else ''
- if append:
- ping_url = '{}/{}'.format(ping_url, append)
- logger.info(
- '{}: Pinging healthchecks.io{}{}'.format(
- config_filename, ' ' + append if append else '', dry_run_label
- )
- )
- logger.debug('{}: Using healthchecks.io ping URL {}'.format(config_filename, ping_url))
- logging.getLogger('urllib3').setLevel(logging.ERROR)
- requests.get(ping_url)
|