mirror of
				https://github.com/kevinveenbirkenbach/computer-playbook.git
				synced 2025-10-31 18:29:21 +00:00 
			
		
		
		
	Optimized auto backup
This commit is contained in:
		| @@ -4,22 +4,18 @@ This Ansible role automates the process of performing backups to a swappable USB | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| - Automatically starts the backup process when a specific USB device is plugged in. | ||||
| - Provides a systemd service to run the backup script at boot if the USB device is already connected. | ||||
| - Supports customization of the backup source path and mount point. | ||||
| - Automatically starts the backup process when mounted to a specific destination. | ||||
| - Supports customization of the backup source path and destination. | ||||
| - Provides a systemd service to run the backup script. | ||||
|  | ||||
| ## Configuration | ||||
| ## Author | ||||
|  | ||||
| The following variables can be customized in the `vars/main.yml` file: | ||||
| This role was created and is maintained by Kevin Veen-Birkenbach. | ||||
|  | ||||
| - `mount_point`: The mount point where the USB device will be mounted. | ||||
| - `backup_to_usb_script_path`: The path to the backup script that will be executed when the USB device is connected. | ||||
| ## License | ||||
|  | ||||
| This code is released under the AGPL v3 license. Please refer to the [LICENSE](LICENSE) file for more details. | ||||
|  | ||||
| ## Credits | ||||
|  | ||||
| This role was created and maintained by Kevin Veen-Birkenbach. | ||||
| Contact: kevin@veen.world | ||||
|  | ||||
| ## More Information | ||||
|  | ||||
| For more details on how the `independent_backup-to-usb` role works, please refer to the Ansible documentation and the role's source code. | ||||
| This software was created with the assistance of [OpenAI ChatGPT](https://chat.openai.com/share/a75ca771-d8a4-4b75-9912-c515ba371ae4). | ||||
							
								
								
									
										60
									
								
								roles/independent_backup-to-usb/files/backup-to-usb.python
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								roles/independent_backup-to-usb/files/backup-to-usb.python
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import sys | ||||
| import subprocess | ||||
| import shutil | ||||
| import os | ||||
| import glob | ||||
| import datetime | ||||
|  | ||||
| def main(): | ||||
|     source_path = sys.argv[1] | ||||
|     print(f"source path: {source_path}") | ||||
|      | ||||
|     backup_to_usb_destination_path = sys.argv[2] | ||||
|     print(f"backup to usb destination path: {backup_to_usb_destination_path}") | ||||
|      | ||||
|     if not os.path.isdir(backup_to_usb_destination_path): | ||||
|         print(f"Directory {backup_to_usb_destination_path} does not exist") | ||||
|         sys.exit(1) | ||||
|      | ||||
|     machine_id = subprocess.run(["sha256sum", "/etc/machine-id"], capture_output=True, text=True).stdout.strip()[:64] | ||||
|     print(f"machine id: {machine_id}") | ||||
|      | ||||
|     versions_path = os.path.join(backup_to_usb_destination_path, f"{machine_id}/backup-to-usb/") | ||||
|     print(f"versions path: {versions_path}") | ||||
|      | ||||
|     if not os.path.isdir(versions_path): | ||||
|         print(f"Creating {versions_path}...") | ||||
|         os.makedirs(versions_path, exist_ok=True) | ||||
|      | ||||
|     previous_version_path = max(glob.glob(f"{versions_path}*"), key=os.path.getmtime, default=None) | ||||
|     print(f"previous versions path: {previous_version_path}") | ||||
|      | ||||
|     current_version_path = os.path.join(versions_path, datetime.datetime.now().strftime("%Y%m%d%H%M%S")) | ||||
|     print(f"current versions path: {current_version_path}") | ||||
|      | ||||
|     print("Creating backup destination folder...") | ||||
|     os.makedirs(current_version_path, exist_ok=True) | ||||
|      | ||||
|     print("Starting synchronization...") | ||||
|     try: | ||||
|         rsync_command = [ | ||||
|             "rsync", "-abP", "--delete", "--delete-excluded", | ||||
|             "--link-dest=" + previous_version_path, | ||||
|             source_path, current_version_path | ||||
|         ] | ||||
|         rsync_output = subprocess.check_output(rsync_command, stderr=subprocess.STDOUT, text=True) | ||||
|          | ||||
|         if "rsync warning: some files vanished before they could be transferred" in rsync_output: | ||||
|             print("Synchronization finished with rsync warning") | ||||
|             sys.exit(0) | ||||
|         else: | ||||
|             print("Synchronization finished") | ||||
|             sys.exit(0) | ||||
|     except subprocess.CalledProcessError as e: | ||||
|         print("Synchronization failed:", e.output) | ||||
|         sys.exit(1) | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
| @@ -1,3 +1,6 @@ | ||||
| --- | ||||
| - name: Reload udev rules | ||||
|   command: udevadm control --reload-rules && udevadm trigger | ||||
| - name: "reload backup-to-usb.service" | ||||
|   systemd: | ||||
|     name: backup-to-usb.service | ||||
|     state: reloaded | ||||
|     enabled: yes | ||||
|     daemon_reload: yes | ||||
|   | ||||
| @@ -1,13 +1,6 @@ | ||||
| --- | ||||
| - name: Copy udev rule to the rules directory | ||||
|   template: | ||||
|     src: 99-usbstick.rules.j2 | ||||
|     dest: /etc/udev/rules.d/ | ||||
|   notify: Reload udev rules | ||||
|  | ||||
| - name: Copy backup script to the scripts directory | ||||
|   template: | ||||
|     src: backup-to-usb.sh.j2 | ||||
|   copy: | ||||
|     src: backup-to-usb.python | ||||
|     dest: "{{ backup_to_usb_script_path }}" | ||||
|     owner: root | ||||
|     group: root | ||||
| @@ -20,9 +13,4 @@ | ||||
|     owner: root | ||||
|     group: root | ||||
|     mode: '0644' | ||||
|  | ||||
| - name: Enable and start service | ||||
|   systemd: | ||||
|     name: backup-to-usb | ||||
|     enabled: yes | ||||
|     state: started | ||||
|   notify: reload backup-to-usb.service | ||||
| @@ -1 +0,0 @@ | ||||
| ACTION=="add", SUBSYSTEM=="block", ENV{ID_SERIAL_SHORT}=="{{ backup_to_usb_serial_short }}", RUN+="/usr/bin/systemd-mount --no-block $devnode {{ mount_point }}", SYMLINK+="backup_usb" | ||||
| @@ -1,10 +1,13 @@ | ||||
| [Unit] | ||||
| Description=Backup to USB when it's plugged in | ||||
| After=local-fs.target | ||||
| Description=Backup to USB when mounted to {{ backup_to_usb_mount }} | ||||
| Wants={{systemctl_mount_service_name}} | ||||
| After={{systemctl_mount_service_name}} | ||||
| OnFailure=systemd-email@%n.service | ||||
| Requires=backups-cleanup.service | ||||
| After=backups-cleanup.service | ||||
|  | ||||
| [Service] | ||||
| ExecStart={{ backup_to_usb_script_path }} {{ mount_point }}/{{ backup_to_usb_subdirectory }} {{ backup_to_usb_source_path }} | ||||
| ExecStart=/bin/python {{ backup_to_usb_script_path }} {{backup_to_usb_source}} {{backup_to_usb_destination}} | ||||
|  | ||||
| [Install] | ||||
| WantedBy=multi-user.target | ||||
| WantedBy=multi-user.target | ||||
| @@ -1,35 +0,0 @@ | ||||
| #!/bin/sh | ||||
| backup_to_usb_destination_path="{{ mount_point }}" && | ||||
| echo "backup to usb destination path: $backup_to_usb_destination_path" && | ||||
|  | ||||
| source_path="{{ backup_to_usb_source_path }}" && | ||||
| echo "source path: $source_path" || exit 1 | ||||
|  | ||||
| if [ ! -d "$backup_to_usb_destination_path" ]; then | ||||
|     echo "Directory $backup_to_usb_destination_path does not exist" && | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| machine_id="$(sha256sum /etc/machine-id | head -c 64 )" && | ||||
| echo "machine id: $machine_id" && | ||||
|  | ||||
| versions_path="$backup_to_usb_destination_path$machine_id/backup-to-usb/" && | ||||
| echo "versions path: $versions_path" || exit 1 | ||||
|  | ||||
| if [ ! -d "$versions_path" ]; then | ||||
|     echo "Creating $versions_path..." && | ||||
|     mkdir -vp $versions_path || exit 1 | ||||
| fi  | ||||
|  | ||||
| previous_version_path="$(ls -d $versions_path* | tail -1)" && | ||||
| echo "previous versions path: $previous_version_path" && | ||||
|  | ||||
| current_version_path="$versions_path$(date '+%Y%m%d%H%M%S')" && | ||||
| echo "current versions path: $current_version_path" && | ||||
|  | ||||
| echo "creating backup destination folder..." && | ||||
| mkdir -vp "$current_version_path" && | ||||
|  | ||||
| echo "Starting synchronization..." | ||||
| rsync -abP --delete --delete-excluded --link-dest="$previous_version_path" "$source_path" "$current_version_path" && | ||||
| echo "Synchronization finished." || exit 1 | ||||
| @@ -1,4 +1,4 @@ | ||||
| --- | ||||
| mount_point: "/mnt/usbstick_{{ backup_to_usb_serial_short }}" | ||||
| backup_to_usb_script_path: "/usr/local/sbin/backup-to-usb.sh" | ||||
| backups_folder_path: "{{mount_point}}{{backup_to_usb_subdirectory}}" | ||||
| backup_to_usb_script_path:    "/usr/local/sbin/backup-to-usb.python" | ||||
| backup_to_usb_destination:    "{{backup_to_usb_mount}}{{backup_to_usb_destination_subdirectory}}" | ||||
| backups_folder_path:          "{{backup_to_usb_destination}}" | ||||
| systemctl_mount_service_name: "{{ backup_to_usb_mount | trim('/') | replace('/', '-') }}.mount" | ||||
		Reference in New Issue
	
	Block a user