Initial commit

This commit is contained in:
Marc Koch 2020-11-23 16:27:19 +01:00
commit 7535298a74
Signed by: marc
GPG Key ID: AC2D4E00990A6767
12 changed files with 190 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
venv/
.idea/
settings.yaml

0
Models/Backup.py Normal file
View File

91
Models/Container.py Normal file
View File

@ -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

View File

@ -0,0 +1,8 @@
class NextcloudBackupException(Exception):
def __init__(self, message):
self.message = message
def __write_to_log(self):
pass

Binary file not shown.

1
README.md Normal file
View File

@ -0,0 +1 @@
nextcloud_docker_scripts

61
backup.py Normal file
View File

@ -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)

17
example_settings.yml Normal file
View File

@ -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"

5
main.py Normal file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env python3
import sys
# check for settings permissions

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
yaml
colorama

1
restore.py Normal file
View File

@ -0,0 +1 @@
#!/usr/bin/env python3

1
upgrade.py Normal file
View File

@ -0,0 +1 @@
#!/usr/bin/env python3