Skip to content

Commit

Permalink
Push version 1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
James Maple authored and James Maple committed Nov 27, 2024
1 parent d1bbdf8 commit d071f9e
Show file tree
Hide file tree
Showing 9 changed files with 376 additions and 16 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,20 @@ This section provides an explanation for each configurable within the config fil
### Retention
| Configurable | Description |
|-------------------------------|---------------------------------------------------------------------------|
| LOCAL_RETENTION_ENABLED | "True" or "False" Enables/Disables retentionc cleanup on the local copy |
| OFFSITE_RETENTION_ENABLED | "True" or "False" Enables/Disables retentionc cleanup on the offsite copy |
| LOCAL_RETENTION_ENABLED | "True" or "False" Enables/Disables retention cleanup on the local copy |
| OFFSITE_RETENTION_ENABLED | "True" or "False" Enables/Disables retention cleanup on the offsite copy |
| LOCAL_RETENTION_PERIOD_DAYS | Store backups for X days. Older backups will be deleted. |
| OFFSITE_RETENTION_PERIOD_DAYS | Store backups for X days. Older backups will be deleted. |


### NTFY
| Configurable | Description |
|-------------------------------|---------------------------------------------------------------------------|
| NTFY_ENABLED | "True" or "False" Enables/Disables Ntfy notifications |
| NTFY_HOST | Ntfy server URL |
| NTFY_TOPIC | Ntfy topic to subscribe to |



______________________
 
Expand Down
5 changes: 5 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## Change log

### V 1.2
- Implement ntfy notifications
- Added some missing error messages before exit conditions


### V 1.1
- Broke changelog out into its own file
- Moved issues from readme to git issues
Expand Down
4 changes: 4 additions & 0 deletions conf/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@ OFFSITE_RETENTION_PERIOD_DAYS =



[NTFY]
NTFY_ENABLED = False
NTFY_HOST = https://ntfy.yourhost.tld
NTFY_TOPIC = CRATE
Binary file modified src/.DS_Store
Binary file not shown.
55 changes: 46 additions & 9 deletions src/crate.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/usr/bin/python3

__author__ = "james_s60"
__date__ = "02 Nov 2024"
__date__ = "27 Nov 2024"
__credits__ = ["james_s60"]
__version__ = "1.1"
__version__ = "1.2"



Expand All @@ -23,6 +23,7 @@
from functions import rwcheck
from functions import script
from functions import sftp
from functions import ntfy


config = ConfigParser()
Expand Down Expand Up @@ -85,6 +86,10 @@
OFFSITE_RETENTION_ENABLED = config['RETENTION'].getboolean('OFFSITE_RETENTION_ENABLED')
LOCAL_RETENTION_PERIOD_DAYS = int(config['RETENTION']['LOCAL_RETENTION_PERIOD_DAYS'])
OFFSITE_RETENTION_PERIOD_DAYS = int(config['RETENTION']['OFFSITE_RETENTION_PERIOD_DAYS'])
# Ntfy
NTFY_ENABLED = config['NTFY'].getboolean('NTFY_ENABLED')
# NTFY_HOST = str(config['NTFY']['NTFY_HOST']) - This is now parsed directly in src/functions/ntfy.py!
# NTFY_TOPIC = str(config['NTFY']['NTFY_TOPIC']) - This is now parsed directly in src/functions/ntfy.py!
############################


Expand All @@ -94,18 +99,28 @@
# Sanity check arguments
if FIX_PERMS == True and RUN_MODE not in {"recover-local", "rl"}:
script.err_msg("Fix Permissions argument specificed but CRATE is running in recovery mode. Program will exit.\n\n")
if NTFY_ENABLED == True:
ntfy.ntfy_err_FP_wrong_mode_fail()
exit()
if RUN_MODE == "backup-local" or RUN_MODE == "bl" and RECOVERY_ZIP is not None:
script.err_msg("Zip file argument specificed but CRATE is running in backup mode. Program will exit.\n\n")
if NTFY_ENABLED == True:
ntfy.ntfy_err_ZIP_wrong_mode_fail()
exit()
if RUN_MODE == "backup-local" or RUN_MODE == "bl" and SKIP_RM is True:
script.err_msg("SRM argument specificed but CRATE is running in backup mode. Program will exit.\n\n")
if NTFY_ENABLED == True:
ntfy.ntfy_err_SRM_wrong_mode_fail()
exit()
if RUN_MODE == "backup-local" or RUN_MODE == "bl" and FIX_PERMS is True:
script.err_msg("Fix Permissions argument specificed but CRATE is running in backup mode. Program will exit.\n\n")
if NTFY_ENABLED == True:
ntfy.ntfy_err_FP_wrong_mode_fail()
exit()
if RUN_MODE == "recover-local" or RUN_MODE == "rl" and RECOVERY_ZIP is None:
script.err_msg("ZIP file not specified. Program will exit.\n\n")
if NTFY_ENABLED == True:
ntfy.ntfy_err_ZIP_missing_fail()
exit()


Expand All @@ -117,39 +132,51 @@

source_dir_readable = rwcheck.check_source_readable(SOURCE_DIR) # Will call exit() if unreadables are found
if source_dir_readable == False:
script.err_msg("Source dir is not readable. Program will exit.\n\n")
if NTFY_ENABLED == True:
ntfy.ntfy_err_source_dir_unreadable_fail()
exit()

dest_dir_writable = rwcheck.check_destination_writable(DEST_DIR) # Will call exit() if unwritable
if dest_dir_writable == False:
script.err_msg("Source dir is not readable. Program will exit.\n\n")
if NTFY_ENABLED == True:
ntfy.ntfy_err_dest_dir_unwriteable_fail()
exit()


if source_dir_readable == True and dest_dir_writable == True:
file.create_hostname_subdirs(HOSTS, DEST_DIR, RUN_MODE)
zip_to_offsite = file.perform_backup_local(SOURCE_DIR, DEST_DIR) # Will call exit() if zip fails validity check

zip_to_offsite = file.perform_backup_local(SOURCE_DIR, DEST_DIR, NTFY_ENABLED)
# Errors & Ntfy are handled within perform_backup_local


# Run retention on local
if LOCAL_RETENTION_ENABLED == True:
script.info_msg("Running retention cleanup on local copy. Retention period: " + str(LOCAL_RETENTION_PERIOD_DAYS) + " days")
retention.localhost_basic_retention(DEST_DIR, LOCAL_RETENTION_PERIOD_DAYS)
retention.localhost_basic_retention(DEST_DIR, LOCAL_RETENTION_PERIOD_DAYS, NTFY_ENABLED)
else:
script.info_msg("Local retention cleanup disabled, skipping retention cleanup.\n\n")


# Ntfy for local backup completion
if NTFY_ENABLED == True:
ntfy.ntfy_ok_local_backup_complete()


# Run Offsite backup
if OFFSITE_BACKUP_ENABLED == True:
script.info_msg("Offsite backup is enabled. Offsite mode: " + str(OFFSITE_BACKUP_MODE))


if OFFSITE_BACKUP_MODE == "local":
file.copy_to_offsite_dir(zip_to_offsite, LOCAL_OFFSITE_BACKUP_DIR, HOSTS)
file.copy_to_offsite_dir(zip_to_offsite, LOCAL_OFFSITE_BACKUP_DIR, HOSTS, NTFY_ENABLED)
#Ntfy handled within function


if OFFSITE_BACKUP_MODE == "sftp":
sftp.copy_to_sftp_dir(zip_to_offsite, HOSTS, SFTP_USER, SFTP_PASS, SFTP_HOST, SFTP_PATH)
sftp.copy_to_sftp_dir(zip_to_offsite, HOSTS, SFTP_USER, SFTP_PASS, SFTP_HOST, SFTP_PATH, NTFY_ENABLED)
#Ntfy handled within function

else:
script.info_msg("Offsite backup disabled, skipping...")
Expand All @@ -161,10 +188,10 @@
script.info_msg("Running retention cleanup on offsite copy. Retention period: " + str(LOCAL_RETENTION_PERIOD_DAYS) + " days")

if OFFSITE_BACKUP_MODE == "local":
retention.localhost_basic_retention(LOCAL_OFFSITE_BACKUP_DIR, LOCAL_RETENTION_PERIOD_DAYS)
retention.localhost_basic_retention(LOCAL_OFFSITE_BACKUP_DIR, LOCAL_RETENTION_PERIOD_DAYS, NTFY_ENABLED)

elif OFFSITE_BACKUP_MODE == "sftp":
retention.sftp_basic_retention(HOSTS, SFTP_USER, SFTP_PASS, SFTP_HOST, SFTP_PATH, OFFSITE_RETENTION_PERIOD_DAYS)
retention.sftp_basic_retention(HOSTS, SFTP_USER, SFTP_PASS, SFTP_HOST, SFTP_PATH, OFFSITE_RETENTION_PERIOD_DAYS, NTFY_ENABLED)

else:
script.info_msg("Offsite retention cleanup disabled, skipping retention cleanup.")
Expand Down Expand Up @@ -202,17 +229,25 @@
recovery_status = file.perform_recovery_local(RECOVERY_ZIP, SOURCE_DIR, SKIP_RM) # Will call exit if no perms to delete SOURCE_DIR and -srm is not used
if recovery_status == "ok":
script.ok_msg("Recovery successful!\n\n")
if NTFY_ENABLED == True:
ntfy.ntfy_ok_recovery_sucess()
if recovery_status == "badzip":
script.err_msg("Recovery failed due to an invalid zip archive. Try again as root or with a different archive.\n\n")
if NTFY_ENABLED == True:
ntfy.ntfy_err_recovery_zip_error()
if recovery_status == "error":
script.err_msg("Recovery failed due to an unknown error. Try again as root or with a different archive.\n\n\\s")
if NTFY_ENABLED == True:
ntfy.ntfy_err_recovery_unknown_error()

if FIX_PERMS == True:
perms_valid = file.sanity_check_permission_config(CONTAINER_USER, PERMISSION)
if perms_valid == True:
file.fix_recovery_permissions(SOURCE_DIR, CONTAINER_USER, PERMISSION) # Will call exit if not running as root
else:
script.err_msg("Permission configuration sanity check failed. Program will now exit...")
if NTFY_ENABLED == True:
ntfy.ntfy_err_recovery_unknown_error()
exit()
else:
script.info_msg("Fix permissions was not specified - skipping... (use -fp and try again as root if this was unintentional)")
Expand All @@ -223,6 +258,8 @@

else:
script.err_msg("Invalid run mode selected.\nRun with -m [bl,rl] or --help for more.\n\n")
if NTFY_ENABLED == True:
ntfy.ntfy_err_invalid_run_mode()
exit()


Expand Down
20 changes: 18 additions & 2 deletions src/functions/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import pwd
import re
from functions import script
from functions import ntfy




Expand Down Expand Up @@ -44,7 +46,7 @@ def create_hostname_subdirs(HOSTS, DEST_DIR, RUN_MODE):



def perform_backup_local(SOURCE_DIR, DEST_DIR):
def perform_backup_local(SOURCE_DIR, DEST_DIR, NTFY_ENABLED):
datetime_str = datetime.datetime.now().strftime('%Y-%m-%d---%H-%M-%S')
hostname = socket.gethostname()
print("\n\n")
Expand All @@ -69,12 +71,14 @@ def perform_backup_local(SOURCE_DIR, DEST_DIR):
except zipfile.BadZipFile:
archive = "bad"
script.warn_msg("The backup archive is potentially corrupt: " + validate_me)
ntfy.ntfy_warn_ZIP_validation_fail()
if archive == 'good':
script.ok_msg("Backup archive passed validation check.")
os.system("rm -rf /tmp/crate-scratch")
script.ok_msg("Backup task complete!\n\n")
else:
script.err_msg("Backup archive FAILED validation check.")
ntfy.ntfy_err_ZIP_validation_fail()

# This is the path of the created backup archive, returned so offsite def can use it
return validate_me
Expand Down Expand Up @@ -118,11 +122,13 @@ def perform_recovery_local(RECOVERY_ZIP, SOURCE_DIR, SKIP_RM):



def copy_to_offsite_dir(zip_to_offsite, OFFSITE_PATH, HOSTS):
def copy_to_offsite_dir(zip_to_offsite, OFFSITE_PATH, HOSTS, NTFY_ENABLED):

# Check if the ZIP file exists
if not os.path.isfile(zip_to_offsite):
script.err_msg(f"The file {zip_to_offsite} does not exist.")
if NTFY_ENABLED == True:
ntfy.ntfy_err_offsite_fail_no_zip()
return

# Check if the destination path is a directory
Expand All @@ -139,9 +145,13 @@ def copy_to_offsite_dir(zip_to_offsite, OFFSITE_PATH, HOSTS):
os.makedirs(hostname_path)
except PermissionError as e:
script.err_msg(f"Permission error while creating directory {hostname_path}: {e}")
if NTFY_ENABLED == True:
ntfy.ntfy_err_offsite_local_fail_dir_create()
return
except Exception as e:
script.err_msg(f"An error occurred while creating directory {hostname_path}: {e}")
if NTFY_ENABLED == True:
ntfy.ntfy_err_offsite_local_fail_dir_create()
return

# Construct the destination path for the copied file
Expand All @@ -152,10 +162,16 @@ def copy_to_offsite_dir(zip_to_offsite, OFFSITE_PATH, HOSTS):
# Copy the file to the destination directory
shutil.copy(zip_to_offsite, destination)
script.ok_msg(f"Successfully copied {zip_to_offsite} to {destination}.")
if NTFY_ENABLED == True:
ntfy.ntfy_ok_offsite_local_complete()
except PermissionError as e:
script.err_msg(f"Permission error: {e}")
if NTFY_ENABLED == True:
ntfy.ntfy_err_offsite_local_fail_copy()
except Exception as e:
script.err_msg(f"An error occurred: {e}")
if NTFY_ENABLED == True:
ntfy.ntfy_err_offsite_local_fail_copy()



Expand Down
Loading

0 comments on commit d071f9e

Please sign in to comment.