Skip to content

Commit 436f861

Browse files
committed
Improved logging of removal of old backups
Added option to dry-run removal of old backups Updated to use the new env variable targetfile instead of tarfile jobFolder is now automatically created if needed Rclone now has hardcoded shell and home due to changes in Proxmox7
1 parent 99266aa commit 436f861

4 files changed

+35
-18
lines changed

ProxmoxEncryptedBackup.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,11 @@ def encryptAndUploadFiles(recipient, sourceDirectory, sourceFiles, destinationFo
117117

118118
def cleanupJobFiles():
119119

120+
120121
if Settings.rcloneRemoveOldBackups:
122+
logging.info("Preparing to remove old backups files from:" + Settings.rcloneRemoteName)
121123
rclone = Rclone.Rclone()
122-
rclone.removeOldFiles(Settings.rcloneRemoveThreshold,Settings.rcloneRemoteName)
124+
rclone.removeOldFiles(Settings.rcloneRemoveThreshold,Settings.rcloneRemoteName, dryRun=Settings.rcloneRemoveOldBackupsDryRun)
123125

124126
logging.info("Preparing to remove old job files from:" + Settings.jobFolder)
125127

@@ -150,13 +152,13 @@ def cleanupJobFiles():
150152
threadFutures = []
151153
threadPool = ThreadPoolExecutor(max_workers=Settings.threads)
152154
for index in filesToEncrypt:
153-
outputFilename = re.search("vzdump-(?:qemu|lxc)-(.*)\.\w*?$", index["tarfile"])[1]
155+
outputFilename = re.search("vzdump-(?:qemu|lxc)-(.*)\.\w*?$", index["targetfile"])[1]
154156
outputFilename += ".enc"
155157
threadFutures.append(
156158
threadPool.submit(encryptAndUploadFiles,
157159
recipient=Settings.gpgRecipient,
158160
sourceDirectory=pathToFiles,
159-
sourceFiles=[index["tarfile"], index["logfile"]],
161+
sourceFiles=[index["targetfile"], index["logfile"]],
160162
destinationFolder=Settings.gpgOutputDirectory,
161163
destinationFileName=outputFilename,
162164
remoteName=Settings.rcloneRemoteName
@@ -176,3 +178,4 @@ def cleanupJobFiles():
176178

177179

178180
cleanupJobFiles()
181+

ProxmoxEncryptedBackupSettings.py

+1
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@
2727
rcloneVerifyUploads = True # If True, after the upload the local and remote files will have their hashes compared
2828
rcloneRemoveSourceFile = True # If True, the upload source file will be deleted after upload. Note this is the .enc file and not the original backup files.
2929
rcloneRemoveOldBackups = False # If True, old remote files will be deleted
30+
rcloneRemoveOldBackupsDryRun = True #If True AND rcloneRemoveOldBackups is True, will only list files that would be deleted
3031
rcloneRemoveThreshold = "14d" # Backups older than this threshold are deleted. Format: ms|s|m|h|d|w|M|y. Example: 14d = 14 days

ProxmoxEventHandler.py

+13-8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ def __init__(self, jobFolder, jobId = None):
2323
logging.info("Job File:" + self.jobFilePath)
2424
logging.debug("Raw Input parameters:" + ",".join(sys.argv))
2525

26+
27+
if not os.path.exists(jobFolder):
28+
logging.debug("Job folder does not already exist, creating it.")
29+
os.makedirs(jobFolder)
30+
2631
parser = argparse.ArgumentParser()
2732
parser.add_argument("phase", help="backup phase")
2833
parser.add_argument("attributes", help="backup attributes mode and vmid", nargs='*')
@@ -149,8 +154,8 @@ def getPhase(self):
149154
dumpdir = os.environ["DUMPDIR"]
150155
storeid = os.environ["STOREID"]
151156
hostname = os.environ["HOSTNAME"]
152-
# tarfile is only available in phase 'backup-end'
153-
tarfile = os.environ["TARFILE"]
157+
# TARGET is only available in phase 'backup-end'
158+
targetfile = os.environ["TARGET"] #Contains the full path to the current VM backup file
154159
# logfile is only available in phase 'log-end'
155160
logfile = os.environ["LOGFILE"]
156161

@@ -171,7 +176,7 @@ def getPhase(self):
171176
'dumpdir': dumpdir,
172177
'storeid': storeid,
173178
'hostname': hostname,
174-
'tarfile': tarfile,
179+
'targetfile': targetfile,
175180
'logfile': logfile,
176181
'mode': mode
177182
}
@@ -189,21 +194,21 @@ def getPhase(self):
189194

190195
'''
191196
192-
Returns a an array with dics with quoted tarfile and logfile elements:
197+
Returns a an array with dics with quoted targetfile and logfile elements:
193198
[
194-
{tarfile: "vzdump-qemu-107-2019_12_29-23_22_54.vma",logfile: "vzdump-qemu-107-2019_12_29-23_22_54.log"},
195-
{tarfile: "vzdump-qemu-108-2019_12_29-23_22_54.vma",logfile: "vzdump-qemu-108-2019_12_29-23_22_54.log"},
199+
{targetfile: "vzdump-qemu-107-2019_12_29-23_22_54.vma",logfile: "vzdump-qemu-107-2019_12_29-23_22_54.log"},
200+
{targetfile: "vzdump-qemu-108-2019_12_29-23_22_54.vma",logfile: "vzdump-qemu-108-2019_12_29-23_22_54.log"},
196201
]
197202
'''
198203
def getFilesFromPhase(self, phase):
199204
logging.debug("Gathering files from phase: " + phase)
200205
filePaths = []
201206

202207
for x in self.jobinfo[phase]:
203-
tarfile = self.jobinfo[phase][x]["tarfile"].split("/")[-1]
208+
targetfile = self.jobinfo[phase][x]["targetfile"].split("/")[-1]
204209
logfile = self.jobinfo[phase][x]["logfile"].split("/")[-1]
205210

206-
filePaths.append({"tarfile" : tarfile, "logfile" : logfile})
211+
filePaths.append({"targetfile" : targetfile, "logfile" : logfile})
207212

208213
logging.debug("Got " + str(len(filePaths) * 2) + " files")
209214

Rclone.py

+15-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class Rclone:
1313
def __init__(self, rcloneLogFilePath=None):
1414

1515
self.rcloneLogFilePath = rcloneLogFilePath
16-
self.bash = pexpect.spawn("/bin/bash", echo=False)
16+
self.bash = pexpect.spawn("/bin/bash", echo=False, env = {"SHELL": "/bin/bash", "HOME": "/root"})
1717

1818
if self.rcloneLogFilePath is not None:
1919
self.bash.logfile = open(rcloneLogFilePath, 'wb')
@@ -35,7 +35,6 @@ def transferSingleFileToRemoteRoot(self, rcloneSourceFile, rcloneRemote, verifyU
3535
rcloneSourceFileName = '"' + rcloneSourceFileName + '"'
3636

3737
logging.info("\tStarting transfer of " + rcloneSourceFile + " to " + rcloneRemote + rcloneSourceFileName)
38-
3938
self.bash.sendline(
4039
f"rclone copyto {rcloneSourceFile} {rcloneRemote}{rcloneSourceFileName} -P ; echo RCLONE FINISHED WITH STATUS $?")
4140

@@ -91,15 +90,24 @@ def transferSingleFileToRemoteRoot(self, rcloneSourceFile, rcloneRemote, verifyU
9190
elif result == 2:
9291
logging.error("\tGdrive upload timed out")
9392
sys.exit(1)
94-
95-
def removeOldFiles(self, tresholdtime, rcloneRemote):
96-
logging.info("\tDelete remote files older then " + tresholdtime)
97-
self.bash.sendline(f"rclone delete --min-age {tresholdtime} {rcloneRemote}; echo DELETEDONE")
93+
94+
def removeOldFiles(self, tresholdtime, rcloneRemote, dryRun:bool = True):
95+
96+
if dryRun:
97+
logging.info("\tRunning dry run of deleting remote files older then " + tresholdtime)
98+
logging.info(f"rclone delete --dry-run --min-age {tresholdtime} {rcloneRemote}; echo DELETEDONE")
99+
self.bash.sendline(f"rclone delete --dry-run --min-age {tresholdtime} {rcloneRemote}; echo DELETEDONE")
100+
else:
101+
logging.info("\tDeleting remote files older then " + tresholdtime)
102+
self.bash.sendline(f"rclone delete --min-age {tresholdtime} {rcloneRemote}; echo DELETEDONE")
98103

99104
result = self.bash.expect(["DELETEDONE", pexpect.TIMEOUT])
100105

106+
deleteOutput = self.bash.before.decode("utf-8")
107+
logging.debug(deleteOutput)
108+
101109
if result == 0:
102-
logging.info("\t Remote files were removed")
110+
logging.info("\t Remote files were removed (Dry Run: " + str(dryRun) + ")")
103111
return True
104112
else:
105113
bashOutput = self.bash.read_nonblocking(size=500, timeout=1)

0 commit comments

Comments
 (0)