bootstrap.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import glob
  2. import importlib
  3. import json
  4. import logging
  5. import os
  6. import borgmatic.borg.pattern
  7. import borgmatic.config.paths
  8. logger = logging.getLogger(__name__)
  9. def use_streaming(hook_config, config): # pragma: no cover
  10. '''
  11. Return whether dump streaming is used for this hook. (Spoiler: It isn't.)
  12. '''
  13. return False
  14. def dump_data_sources(
  15. hook_config,
  16. config,
  17. config_paths,
  18. borgmatic_runtime_directory,
  19. patterns,
  20. dry_run,
  21. ):
  22. '''
  23. Given a bootstrap configuration dict, a configuration dict, the borgmatic configuration file
  24. paths, the borgmatic runtime directory, the configured patterns, and whether this is a dry run,
  25. create a borgmatic manifest file to store the paths of the configuration files used to create
  26. the archive. But skip this if the bootstrap store_config_files option is False or if this is a
  27. dry run.
  28. Return an empty sequence, since there are no ongoing dump processes from this hook.
  29. '''
  30. if hook_config and hook_config.get('store_config_files') is False:
  31. return []
  32. borgmatic_manifest_path = os.path.join(
  33. borgmatic_runtime_directory, 'bootstrap', 'manifest.json'
  34. )
  35. if dry_run:
  36. return []
  37. os.makedirs(os.path.dirname(borgmatic_manifest_path), exist_ok=True)
  38. with open(borgmatic_manifest_path, 'w') as manifest_file:
  39. json.dump(
  40. {
  41. 'borgmatic_version': importlib.metadata.version('borgmatic'),
  42. 'config_paths': config_paths,
  43. },
  44. manifest_file,
  45. )
  46. patterns.extend(borgmatic.borg.pattern.Pattern(config_path) for config_path in config_paths)
  47. patterns.append(
  48. borgmatic.borg.pattern.Pattern(os.path.join(borgmatic_runtime_directory, 'bootstrap'))
  49. )
  50. return []
  51. def remove_data_source_dumps(hook_config, config, borgmatic_runtime_directory, dry_run):
  52. '''
  53. Given a bootstrap configuration dict, a configuration dict, the borgmatic runtime directory, and
  54. whether this is a dry run, then remove the manifest file created above. If this is a dry run,
  55. then don't actually remove anything.
  56. '''
  57. dry_run_label = ' (dry run; not actually removing anything)' if dry_run else ''
  58. manifest_glob = os.path.join(
  59. borgmatic.config.paths.replace_temporary_subdirectory_with_glob(
  60. os.path.normpath(borgmatic_runtime_directory),
  61. ),
  62. 'bootstrap',
  63. )
  64. logger.debug(
  65. f'Looking for bootstrap manifest files to remove in {manifest_glob}{dry_run_label}'
  66. )
  67. for manifest_directory in glob.glob(manifest_glob):
  68. manifest_file_path = os.path.join(manifest_directory, 'manifest.json')
  69. logger.debug(
  70. f'Removing bootstrap manifest at {manifest_file_path}{dry_run_label}'
  71. )
  72. if dry_run:
  73. continue
  74. try:
  75. os.remove(manifest_file_path)
  76. except FileNotFoundError:
  77. pass
  78. try:
  79. os.rmdir(manifest_directory)
  80. except FileNotFoundError:
  81. pass
  82. def make_data_source_dump_patterns(
  83. hook_config, config, borgmatic_runtime_directory, name=None
  84. ): # pragma: no cover
  85. '''
  86. Restores are implemented via the separate, purpose-specific "bootstrap" action rather than the
  87. generic "restore".
  88. '''
  89. return ()
  90. def restore_data_source_dump(
  91. hook_config,
  92. config,
  93. data_source,
  94. dry_run,
  95. extract_process,
  96. connection_params,
  97. borgmatic_runtime_directory,
  98. ): # pragma: no cover
  99. '''
  100. Restores are implemented via the separate, purpose-specific "bootstrap" action rather than the
  101. generic "restore".
  102. '''
  103. raise NotImplementedError()