Commit befcd677 authored by Tim Bleimehl's avatar Tim Bleimehl 🤸🏼
Browse files


parent 54d9834d
......@@ -151,5 +151,6 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
......@@ -572,10 +572,41 @@ def auto_create_kubernetes(namespace, all_namespaces):
click.echo(f"Created {count_dbs} database(s) in {count_db_instances} instance(s)")
def auto_create_docker():
# you are here. maybe we dont new "now" command and instead a kubernetes and a docker version
from container_helper import ContainerHelper
count_db_instances = 0
count_dbs = 0
for container in ContainerHelper.docker_get_container_to_be_backed_up():
count_db_instances += 1
if container.coda_labels[ValidLabels.enabled].val:
BackupperClass = database_type_backupper_mapping[
bu: BaseBackupper = BackupperClass(container)
created_dbs = bu.auto_create()
if created_dbs:
count_dbs += len(created_dbs)
click.echo(f"Created {count_dbs} database(s) in {count_db_instances} instance(s)")
def list_labels():
help="Define the output format: 'human' an easy to read table, 'json' or 'yaml' for inter-process readability, dict if used in a python script",
type=click.Choice(["human", "json", "yaml", "dict"], case_sensitive=False),
def list_labels(output_format):
output = ValidLabels.list_labels(output_format)
return output
if __name__ == "__main__":
......@@ -172,7 +172,7 @@ class ContainerHelper:
raise NotImplementedError(
f"Can not query pods of workload. Unknown workload format. Expected to find keys 'spec.selector.matchLabels' in Workload. got \n\n{workload}\n\n"
pod_selector_labels: List[Label] = Label.from_dict(
pod_selector_labels: List[Label] = Label.dict_to_label(
for wl_pod in cls.kubernetes_get_pods(
from distutils import util
from typing import List, Dict, Type, Any, Union
import json
import yaml
import copy
import logging
......@@ -46,12 +48,24 @@ class Label: str = info
def from_dict(cls, labels: dict) -> List["Label"]:
def dict_to_label(cls, labels: dict) -> List["Label"]:
l = []
for key, val in labels.items():
l.append(Label({key: val}))
return l
def to_dict(self, hide_val: bool = False) -> Dict:
lbl_dict = {
"key": self.key,
"type": self.type.__name__,
"possible_values": self.possible_values,
"default": self.default,
if not hide_val:
lbl_dict["value"] = self.val
return lbl_dict
def __eq__(self, other: Union["Label", str]):
return (
type(other) is type(self)
......@@ -279,16 +293,32 @@ class ValidLabels:
return lbls
def list_labels_human_readable(cls):
# ToDo: make this better readable for humans
s = ""
for label in cls.iter():
s += f"\n{label.key} \n"
s += f" type: {label.type.__name__}\n"
if label.default is not None:
s += f" default: {label.default}\n"
if label.possible_values:
s += f" possible_values: {label.possible_values}\n"
s += f" {}\n"
return s
def list_labels(cls, format: str = "human"):
if format == "human":
# ToDo: make this better readable for humans
s = ""
for label in cls.iter():
s += f"\n# {label.key} \n"
s += f"\ttype: {label.type.__name__}\n"
if label.default is not None:
s += f"\tdefault: {label.default}\n"
if label.possible_values:
s += f"\tpossible_values: {label.possible_values}\n"
s += f" {}\n"
return s
elif format in ["yaml", "json", "dict"]:
lbls = []
for label in cls.iter():
if format == "yaml":
return yaml.dump(lbls)
elif format == "json":
return json.dumps(lbls)
return lbls
raise ValueError(
"Expected format to be on of ['human','json','yaml','dict'] got '{format}'"
......@@ -26,4 +26,4 @@ if __name__ == "__main__":
# mysql.restore("redcado","mysqlbackup_2021-12-29_14-19-40")
......@@ -4,7 +4,7 @@ A container native database backup and restore solution
Status: Alpha (WIP - not basic-feature completed yet)
Status: Alpha (WIP - **do not use productive yet**)
# What is this (short)
......@@ -78,17 +78,15 @@ Thats it. We now have a directory `./backups/` in front of us, with all database
* Automatic backup retentation management (Daily, Weekly, Monthly, Yearly)
* "Backup now!" wizard
* Compressed backup
* Auto create databases and users
# Planned features
* (WIP) Restore Wizard
* (WIP) Neo4j support
* (WIP) Auto database creation if not exists
* (WIP) Create database if not existent via label conf (checked/executed when pod starts via
* (Planned) Database auth via Docker/kubernetes Secrets
* (Planned) Email notification
* (Planned) Docker Event listener / Kubectl hooks to react to container started/stopped
* (Planned) Improve human readable output by printing a tree structure (
* (Planned) Backup compression optional
* (Idea) Switch to and (or create alternative modules)
* (Idea) restore by label (checked/executed when pod starts via (needs a metadata store :/ )
......@@ -97,6 +95,7 @@ Thats it. We now have a directory `./backups/` in front of us, with all database
* (Idea) [LCX]( support. Help needed!
* (Idea) Suppord pod with more than one container
* (Idea) Provide auto-create params in instead of k8s annotation
* (Idea) Improve human readable output by printing a tree structure (
# Current ToDo
......@@ -7,17 +7,19 @@ COPY --from=docker:latest /usr/local/bin/docker /usr/local/bin/
# install python3
RUN install_packages python3 python3-pip
# install required python modules
COPY reqs.txt /tmp/reqs.txt
RUN pip3 install --no-cache-dir -r /tmp/reqs.txt
RUN pip3 install setuptools
# copy backupper python scripts
COPY . /opt/CoDaBackup
RUN pip3 install -e /opt/CoDaBackup
# Switch back to non root user
#USER 1001
# copy backupper python scripts
COPY sqlbackupper /opt/sqlbackupper
# Set config to "DOCKER"-Profile (see
# Volume for backup dir
VOLUME ["/backup"]
ENTRYPOINT [ "/opt/sqlbackupper/" ]
ENTRYPOINT [ "/opt/CoDaBackup/CoDaBackup/" ]
CMD [ "--help" ]
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment