Initial commit
This commit is contained in:
commit
7535298a74
|
|
@ -0,0 +1,3 @@
|
|||
venv/
|
||||
.idea/
|
||||
settings.yaml
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
import datetime
|
||||
import os
|
||||
import stat
|
||||
import tarfile
|
||||
from Models.NextcloudBackupException import NextcloudBackupException
|
||||
|
||||
|
||||
class Container:
|
||||
|
||||
def __init__(self, name, password, backup_folder, compose_file_path) -> None:
|
||||
self.__datetime = datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S")
|
||||
self.name = name
|
||||
self.__password = password
|
||||
self.backup_folder = backup_folder
|
||||
self.compose_file_path = compose_file_path
|
||||
self.__dump_file = self.name + '_' + self.__datetime + '.sql'
|
||||
self.__dump_file_path = os.path.join(self.backup_folder, self.__dump_file)
|
||||
self.__tar_file = self.name + '_' + self.__datetime + 'tar.gz'
|
||||
self.__tar_file_path = os.path.join(self.backup_folder, self.__tar_file)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return F"name: {self.name}\npassword: {self.__password}\ncompose_file_path: {self.compose_file_path}"
|
||||
|
||||
# Create backup folder if it does not yet exist
|
||||
def create_backup_dir(self):
|
||||
if not os.path.isfile(self.backup_folder):
|
||||
try:
|
||||
os.makedirs(self.backup_folder)
|
||||
except OSError as e:
|
||||
raise OSError(e)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# Dump database
|
||||
def __dump_db(self) -> bool:
|
||||
try:
|
||||
os.system(F"docker exec {self.name} mysqldump --password={self.__password} --all-databases > "
|
||||
F"{self.__dump_file}")
|
||||
return os.path.isfile(self.__dump_file)
|
||||
except Exception as e:
|
||||
raise Exception(e)
|
||||
|
||||
# Tar config and settings folder within container and copy it into backup folder
|
||||
def __export_config(self) -> bool:
|
||||
try:
|
||||
os.system(F"docker exec {self.name} tar -czf config_settings.tar config settings")
|
||||
os.system(F"docker cp {self.name}:/var/www/html/config_settings.tar {self.__tar_file_path}")
|
||||
os.system(F"docker exec {self.name} rm config_settings.tar")
|
||||
return os.path.isfile(self.__tar_file_path)
|
||||
except Exception as e:
|
||||
raise NextcloudBackupException(e)
|
||||
|
||||
# Tar database with config and settings
|
||||
def __tar_db(self) -> bool:
|
||||
try:
|
||||
with tarfile.open(self.__tar_file_path, 'w:gz') as tarball:
|
||||
tarball.add(self.__dump_file_path, arcname=self.__dump_file)
|
||||
return tarball.gettarinfo(self.__dump_file).isfile()
|
||||
except Exception as e:
|
||||
raise NextcloudBackupException(e)
|
||||
|
||||
# Set secure file permissions
|
||||
def __set_file_permissions(self) -> bool:
|
||||
try:
|
||||
os.chmod(self.__tar_file_path, stat.S_IREAD)
|
||||
return oct(os.stat(self.__tar_file_path).st_mode)[-3:] == 600
|
||||
except Exception as e:
|
||||
raise NextcloudBackupException(e)
|
||||
|
||||
# Create backup
|
||||
def create_backup(self) -> dict:
|
||||
try:
|
||||
return {"database dump": self.__dump_db(),
|
||||
"export config": self.__export_config(),
|
||||
"include db in backup": self.__tar_db(),
|
||||
"set secure backup file permissions": self.__set_file_permissions()}
|
||||
except NextcloudBackupException as e:
|
||||
raise NextcloudBackupException(e)
|
||||
|
||||
@staticmethod
|
||||
def deserialize_containers(data: dict) -> list:
|
||||
containers = []
|
||||
for name, values in data['nextcloud_containers'].items():
|
||||
containers.append(Container(
|
||||
name,
|
||||
values['mysql_password'],
|
||||
values['backup_folder'],
|
||||
values['compose_file_path'])
|
||||
)
|
||||
return containers
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
class NextcloudBackupException(Exception):
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
|
||||
def __write_to_log(self):
|
||||
pass
|
||||
Binary file not shown.
|
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
from colorama import Fore, Style
|
||||
import Models.Backup
|
||||
from Models.Container import Container
|
||||
from Models.NextcloudBackupException import NextcloudBackupException
|
||||
|
||||
|
||||
def backup(container_names=None):
|
||||
global backup_successfull
|
||||
with open(r"./settings.yaml") as file:
|
||||
# Load settings
|
||||
settings_list = yaml.full_load(file)
|
||||
log_file = settings_list['paths']['log_file']
|
||||
containers = Container.deserialize_containers(settings_list)
|
||||
|
||||
if type(container_names) is list:
|
||||
containers_tmp = []
|
||||
for container_name in container_names:
|
||||
if container_name is str and container_name in containers:
|
||||
containers_tmp.append(containers[container_name])
|
||||
else:
|
||||
print(F"{Fore.RED}Cannot find configuration for {container_name} in settings.yaml{Style.RESET_ALL}")
|
||||
containers = containers_tmp
|
||||
|
||||
# Loop through Nextcloud container instances
|
||||
container: Container
|
||||
for container in containers:
|
||||
# Create backup folder if it does not yet exist
|
||||
if container.create_backup_dir():
|
||||
try:
|
||||
print(F"{Fore.GREEN}Backup folder created under: {container.backup_folder}{Style.RESET_ALL}")
|
||||
except OSError as e:
|
||||
sys.exit(F"{Fore.RED}Could not create backup folder: {e.strerror}{Style.RESET_ALL}")
|
||||
|
||||
print(F"Starting backup for {container.name}:")
|
||||
try:
|
||||
backup_successfull = True
|
||||
for key, status in container.create_backup():
|
||||
if status is True:
|
||||
print(F"{Fore.GREEN}{key}: success{Style.RESET_ALL}")
|
||||
else:
|
||||
print(F"{Fore.RED}{key}: failed{Style.RESET_ALL}")
|
||||
backup_successfull = False
|
||||
except NextcloudBackupException as e:
|
||||
print(F"{Fore.RED}Backup for {container.name} failed!/n{e.message}{Style.RESET_ALL}")
|
||||
print("---------------------------------")
|
||||
if backup_successfull is True:
|
||||
print(F"{Fore.GREEN}Backup for {container.name} was successful{Style.RESET_ALL}")
|
||||
else:
|
||||
print(F"{Fore.RED}Backup for {container.name} failed{Style.RESET_ALL}")
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
backup(sys.argv)
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
nextcloud_containers:
|
||||
|
||||
instance1: # name like Nextcloud container instance
|
||||
mysql_password: "password"
|
||||
backup_folder: "/full/path/to/directory/"
|
||||
compose_file_path: "/full/path/to/directory/"
|
||||
|
||||
instance2: # name like Nextcloud container instance
|
||||
mysql_password: "password"
|
||||
backup_folder: "/full/path/to/directory/"
|
||||
compose_file_path: "/full/path/to/directory/"
|
||||
|
||||
log:
|
||||
text: true
|
||||
json: false
|
||||
log_file: "/full/path/to/file.log"
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
import sys
|
||||
|
||||
# check for settings permissions
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
yaml
|
||||
colorama
|
||||
|
|
@ -0,0 +1 @@
|
|||
#!/usr/bin/env python3
|
||||
|
|
@ -0,0 +1 @@
|
|||
#!/usr/bin/env python3
|
||||
Loading…
Reference in New Issue