Skip to content

Commit

Permalink
now retention can be set, destination folder and the config is integr…
Browse files Browse the repository at this point in the history
…ated in one file
  • Loading branch information
rlunaro committed Jan 15, 2024
1 parent f0f5bdf commit df0e7bc
Show file tree
Hide file tree
Showing 11 changed files with 449 additions and 157 deletions.
6 changes: 1 addition & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
# never is shared publcly. The NOTES.* and
# SECRETS.* files are for internal documentation
#
NOTES.md
NOTES.html
SECRETS.md
SECRETS.html
config.yaml
PRIVATE/
site/
data/
Expand All @@ -19,7 +16,6 @@ data/
.project
.pydevproject
token.pickle
config.json
__pycache__

*~
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.0.0
2.1.0
5 changes: 1 addition & 4 deletions deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,7 @@ def add_file_dir( zipfile:object, file_path:str, archive_name:str ) -> None :
add_file_dir( deployment, 'src/service_google_drive.py', 'service_google_drive.py' )
add_file_dir( deployment, 'src/verify_stragegy.py', 'verify_stragegy.py' )

add_file_dir( deployment, 'email_failure_template.txt', 'email_failure_template.txt' )
add_file_dir( deployment, 'email_success_template.txt', 'email_success_template.txt' )
add_file_dir( deployment, 'example-config.json', 'example-config.json' )
add_file_dir( deployment, 'logging.json', 'logging.json' )
add_file_dir( deployment, 'example-config.yaml', 'example-config.yaml' )

add_file_dir( deployment, 'drive-backup.cmd', 'drive-backup.cmd' )
add_file_dir( deployment, 'drive-backup.sh', 'drive-backup.sh' )
Expand Down
37 changes: 0 additions & 37 deletions example-config.json

This file was deleted.

128 changes: 128 additions & 0 deletions example-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#
# config.yaml - configuration file for google-drive-backup
#

#
# reporting: the implemented method for reporting is send an email,
# and here are the configuration data
#
reportEmail:
emailFrom : "YOUR GOOGLE EMAIL ACCOUNT HERE"
emailTo : ["A LIST OF EMAILS TO NOTIFY, CAN BE LEFT EMPTY"]
# template of the "success" notification email, customize to suit your
# needs/language. The placeholders {day} and {hour} will be replaced
# by the day and hour of the copies, in day/month format.
emailSuccess :
subject : "OK: Copia de seguridad realizada con éxito el {day} a las {hour}"
body: >
Hola caraguapa:
El {day}, a las {hour} se ha realizado con éxito la copia de seguridad.
{report}
{backupPolicyExplanation}
Saludos,
El robot más caraguapa del mundo
emailFailure :
subject : "FAIL: Copia de seguridad HA FALLADO {day} a las {hour}"
body: >
Hola caraguapa:
Me temo que se ha producido un error en la copia de seguridad planificada para el día {day} a las {hour}.
El error que ha aparecido es:
{error_description}
Posiblemente la copia no se haya realizado. Conviene echar un vistazo cuanto antes.
Saludos,
El robot más caraguapa del mundo
#
# resources to backup configuration section
#

# do you need to do do something before or after
# the copies are made??? -like run a script to collect
# the backup copies, or stop a website or something like that-
# if so, you can configure it here
runBefore : ["/home/rluna/wkpy/google-drive-backup/data/database_backup.sh"]
runAfter : []

# the list of directories to backup (must NOT END in "/")
resourcesToBackup :
- "../data"

# Set this value to "true" if you want to
# verify the uploaded files
verifyUploadedFiles : true



#
# backup policies
#
# by default, three different policies can be configured: daily, monthly
# and yearly. The "daily" copies are made each day, and are stored in the
# indicated folder (in this example in the folder 01_diarios). Not all days
# are saved, only the last X days. That X is set in the retention. For
# instance, if you set a retention of 3, only 3 copies will be stored.
#
backupPolicy:
destinationFolder : "backup"
daily :
folder: "01_daily"
# how many different copies do you want to keep
retention : 3
monthly :
folder: "02_monthly"
#
# yearly:
# folder: "my_yearly_copies"
# retention: 10 # keep 10 years of copies
#


#
# config info for credentials.jsonfile
#
# you have to recover this information from google
# cloud console, after creating your own application
#
installed: null


#
# logging configuration: can be omitted if you want
#
logging:
version: 1
formatters:
formatter1:
format: "%(asctime)s %(levelname)-8s %(message)s"
datefmt: "%Y-%m-%d %H:%M"
handlers:
handler1:
class: "logging.handlers.RotatingFileHandler"
encoding : "utf-8"
filename : "drive-backup.log"
# 1 Mb
maxBytes : 1024000
backupCount : 3
formatter: formatter1
loggers:
rotatingFileLogger:
level: DEBUG
handlers: [ "handler1" ]
root:
handlers : [ "handler1" ]
level : DEBUG




114 changes: 91 additions & 23 deletions src/backup_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,75 +19,143 @@
'''

import datetime
from http.cookiejar import EPOCH_YEAR

class BackupPolicy(object):
'''
determine the backup policy to apply
'''
DAILY_TEXT = """La carpeta {folder}, contiene las copias diarias que se
hacen. Sólo se hacen {retention}: una de las carpetas contiene la
más reciente y el resto contienen las de días anteriores: el sistema
va rotando para mantener sólo ése número de copias."""
MONTLY_TEXT = """La segunda carpeta, {folder}, contiene las copias que se hacen
los días 1 de cada mes. Sólo se hacen {retention}: una de las carpetas contiene la
más reciente y el resto contienen las de meses anteriores: el sistema
va rotando para mantener sólo ése número de copias."""
YEARLY_TEXT = """La tercera carpeta, {folder}, contiene las copias que se hacen los
días 30/12 (el penúltimo día del año). Se retienen sólamente {retention} copias, por
el mismo algoritmo que en los casos anteriores: el programa va buscando qué carpeta
toca y deja ahí la copia del año, de forma que sólo tendrás {retention} copias anuales."""

DEFAULT_RETENTIONS = { "daily" : 10,
"monthly" : 13,
"yearly" : 10 }

def __init__(self, today = datetime.datetime.today() ):
def __init__(self,
backupPolicy: dict,
today = datetime.datetime.today() ):
self._backupPolicy = backupPolicy
self._today = today

def explain(self):
return '''
policy_explanation = '''
Una breve nota sobre la política de respaldo:
En la carpeta "backup" encontrarás tres directorios: 01_diarios,
02_mensuales, 03_anuales.
En la carpeta "{destinationFolder}" encontrarás {numberOfFolders}
directorios: {foldersAsList}.
La primera carpeta, 01_diarios, contiene las copias diarias que se
hacen. Solo se hacen 10, coincidiendo con el último dígito del día.
Por ejemplo, si hoy es día 25, las copias que se hayan hecho en la
noche del 24 al 25 (que es día 25), irán a la carpeta "5".
{dailyExplanationIfNeeded}
La segunda carpeta, 02_menusales, contiene las copias que se hacen
los días 1 de cada mes. Van por meses; es decir en la 05 encontrarás
la copia que se hizo el 01/05, es decir, la de primeros de Mayo.
{monthlyExplanationIfNeeded}
La tercera carpeta, 03_anuales, contiene las copias que se hacen los
días 30/12 (el penúltimo día del año). Van por el último dígito del
año. Es decir, para el año 2019 la copia irá al 03_anuales/9. Para el
año 2020, la copia irá al 03_anuales/0.
{yearlyExplanationIfNeeded}
'''
return policy_explanation.format(
destinationFolder = self._backupPolicy["destinationFolder"],
numberOfFolders = self._numberOfFolders(),
foldersAsList = self._foldersAsList(),
dailyExplanationIfNeeded = self._explanationOrNothing( "daily", self.DAILY_TEXT ),
monthlyExplanationIfNeeded = self._explanationOrNothing( "monthly", self.MONTLY_TEXT ),
yearlyExplanationIfNeeded = self._explanationOrNothing( "yearly", self.YEARLY_TEXT ) )

def _numberOfFolders(self):
folders = 0
for key in ["daily", "monthly", "yearly"]:
if key in self._backupPolicy.keys() and self._backupPolicy[key]:
folders += 1
return folders

def _foldersAsList(self):
folders = ""
for key in ["daily", "monthly", "yearly"]:
if key in self._backupPolicy.keys() and self._backupPolicy[key]:
if folders != "":
folders += ", "
folders += self._backupPolicy[key]["folder"]
return folders

def _explanationOrNothing(self, key : str, text : str):
if key in self._backupPolicy.keys():
folder = self._backupPolicy[key].get("folder", "")
retention = self._backupPolicy[key].get("retention", self.DEFAULT_RETENTIONS[key])
explanation = text.format(
folder = folder,
retention = retention )
return explanation
return ""

def isDailyPolicy(self):
'''
the daily policy is enforceable everytime the
program is invoked
program is invoked given that is configured
'''
return True
return self._backupPolicy.get("daily", False)

def isMonthlyPolicy(self):
'''
the montly policy is enforceable the day 1 of each month
given that is configured
'''
return self._today.day == 1
return (self._backupPolicy.get("monthly", False)
and self._today.day == 1)

def isYearlyPolicy(self):
'''
the yearly policy is enforceable the day 12/30 of each year
(we will avoid to use the 12/31 date)
given that is configured
'''
return (self._today.month == 12 and self._today.day == 30)
return (self._backupPolicy.get("yearly", False)
and self._today.month == 12
and self._today.day == 30)

def getDailyPolicyFolder(self):
return self._backupPolicy["daily"]["folder"]

def getDailyDir(self):
'''
for each day, return the modulus 10 of the day,
11 -> '1'
1 -> '1'
'''
return '{:01d}'.format( self._today.day % 10 )
try:
daily_retention = self._backupPolicy["daily"]["retention"]
except:
daily_retention = self.DEFAULT_RETENTIONS["daily"]
return '{:01d}'.format( self._today.day % daily_retention )

def getMonthlyPolicyFolder(self):
return self._backupPolicy["monthly"]["folder"]

def getMonthlyDir(self):
return '{:02d}'.format( self._today.month )
try:
monthly_retention = self._backupPolicy["monthly"]["retention"]
except:
monthly_retention = self.DEFAULT_RETENTIONS["monthly"]
return '{:02d}'.format( self._today.month % monthly_retention )

def getYearlyPolicyFolder(self):
return self._backupPolicy["yearly"]["folder"]

def getYearlyDir(self):
'''
2019 -> '9'
2020 -> '0'
'''
return '{:01d}'.format( self._today.year % 10)
try:
yearly_retention = self._backupPolicy["yearly"]["retention"]
except:
yearly_retention = self.DEFAULT_RETENTIONS["yearly"]
return '{:01d}'.format( self._today.year % yearly_retention)


Loading

0 comments on commit df0e7bc

Please sign in to comment.