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

wip

parent ab40dd85
......@@ -19,12 +19,7 @@ class BaseBackupper:
backup_file_prefix: str = None
backup_file_suffix: str = None
dir_backups: str = config.BACKUP_DIR
ignore_databases: List[str] = [
"performance_schema",
"information_schema",
"mysql",
"sys",
]
ignore_databases: List[str] = []
def __init__(
self,
......
......@@ -63,7 +63,7 @@ def backup_cli(debug):
log.setLevel("DEBUG")
@backup_cli.command()
@backup_cli.command(name="now")
@click.option(
"--mode",
default="Docker",
......@@ -73,7 +73,7 @@ def backup_cli(debug):
)
@click.option(
"--container-identifier",
prompt="Container/pod name(s) (seperated by comma)? (Ignore question in `native` mode)",
prompt="(k8s-namespace)/Containername? e.g.: 'default/mariadb01-0' in k8s or 'mariadb01' in docker",
help="The Docker container name/id (as in `docker ps`) or kubernetes pod name. Split by ',' if multiple",
)
@click.option(
......@@ -107,13 +107,6 @@ def backup_cli(debug):
prompt="Database(s) to backup ('mydb' or ['mydb01', 'mydb02'])? Leave empty for all DBs.",
help="The Databases to backup. We can select a specific database by name . e.g. 'my_database01' or a list of databases e.b. ['mydb01', 'mydb02']. If left empty all databses accessable for the user will be backuped.",
)
@click.option(
"--backup-retention-type",
default=RetentionType.MANUAL,
prompt="Backup retention type?",
help="This defines in which directory the backup lands in?",
type=click.Choice([r.value for r in RetentionType], case_sensitive=False),
)
def backup_now(
mode,
container_identifier,
......@@ -122,13 +115,16 @@ def backup_now(
database_user,
database_password,
database_names,
backup_retention_type,
):
"""Wizard to backup a specific database, now!"""
container_names = container_identifier.split(",")
for container_name in container_names:
exe = Executer(mode, container_name)
if mode == "kubernetes":
namespace, container_name_ = container_name.split("/")
exe = Executer(mode, container_name_, namespace=namespace)
else:
exe = Executer(mode, container_name)
BackupperClass = database_type_backupper_mapping[database_type]
bu = BackupperClass(
......@@ -139,7 +135,7 @@ def backup_now(
)
bu.backup(
databases=database_names,
retention_type=RetentionType(backup_retention_type),
retention_type=RetentionType.MANUAL,
)
......@@ -164,15 +160,7 @@ def backup_now(
default=None,
help=f"Where to store the backups. Will default to '{ValidLabels.backup_dir.val}'",
)
@click.option(
"--exclude-namespace-from-path",
"-e",
default=False,
help=f"By default the kubernetes namespace of a database workload will be included in the backup path to prevent name collisions. Attach this flag to prevent this and have a flatter directory structure, if you are sure your workloads have uniqe names over all namespaces. Alternatively set the label '{str(ValidLabels.backup_dir)}' on a per workload base",
)
def backup_kubernetes(
namespace, all_namespaces, target_dir, exclude_namespace_from_path
):
def backup_kubernetes(namespace, all_namespaces, target_dir):
"""Backup databases in a kubernetes environment"""
from container_helper import ContainerHelper
......@@ -210,9 +198,7 @@ def backup_kubernetes(
target_dir
if target_dir
else pod.backup_labels[ValidLabels.backup_dir].val,
pod.parent["metadata"]["namespace"]
if not exclude_namespace_from_path
else "",
pod.parent["metadata"]["namespace"],
pod.parent["metadata"]["name"],
)
)
......@@ -419,19 +405,12 @@ def restore_kubernetes(ctx, namespace, all_namespaces, pod_name, backup_name):
default=None,
help=f"Where to look for the backups. Will default to '{ValidLabels.backup_dir.val}'",
)
@click.option(
"--exclude-namespace-from-path",
"-e",
default=False,
help=f"By default the kubernetes namespace of a database workload will be included in the backup path to prevent name collisions. Attach this flag to prevent this and have a flatter directory structure, if you are sure your workloads have uniqe names over all namespaces. Alternatively set the label '{str(ValidLabels.backup_dir)}' on a per workload base",
)
@click.option("--yaml", default=False, help="Output list machine readable")
def restore_kubernetes_list(
pod_name,
databases,
namespace,
all_namespaces,
exclude_namespace_from_path,
yaml,
source_dir,
):
......@@ -457,9 +436,7 @@ def restore_kubernetes_list(
source_dir
if source_dir
else pod.backup_labels[ValidLabels.backup_dir].val,
pod.parent["metadata"]["namespace"]
if not exclude_namespace_from_path
else "",
pod.parent["metadata"]["namespace"],
pod.parent["metadata"]["name"],
)
)
......
......@@ -41,7 +41,7 @@ class Container:
)
@classmethod
def from_kubernetes_get(cls, kubectl_get_item_result: dict):
def from_kubernetes_get_dict(cls, kubectl_get_item_result: dict):
# todo validate correct item by "kind" field
return cls(
id=kubectl_get_item_result["metadata"]["uid"],
......@@ -62,6 +62,7 @@ class ContainerHelper:
def kubernetes_get_pods(
cls,
labels: List[Label] = None,
pod_name: str = None,
namespace: str = None,
all_namespaces: bool = False,
describe: bool = False,
......@@ -83,16 +84,29 @@ class ContainerHelper:
namespace_arg = (
f"-n {namespace if namespace else config.KUBECTL_DEFAULT_NAMESPACE}"
)
labels_str: str = ",".join([str(label) for label in labels])
selector_arg: str = f"--selector '{labels_str}'" if labels_str else ""
if pod_name:
selector_arg = pod_name
elif labels:
labels_str: str = ",".join([str(label) for label in labels])
selector_arg: str = f"--selector '{labels_str}'" if labels_str else ""
elif pod_name and labels:
raise NotImplementedError(
f"You tried to filter by pod name '{pod_name}' and lables '{labels}'. Only one filter is applieable"
)
pod_descs: Dict = json.loads(
Executer.exec(
f"{config.KUBECTL_COMMAND} get pods {namespace_arg} {selector_arg} -o json"
)
)["items"]
)
if pod_descs["kind"] == "List":
# we have multiple pods as result. lets extraxt the list of pods
pod_descs = pod_descs["items"]
elif pod_descs["kind"] == "Pod":
# we have a single pod. lets put in a list to keep the format consistently
pod_descs = [pod_descs]
pods: List[Container] = []
for pod_desc in pod_descs:
pods.append(Container.from_kubernetes_get(pod_desc))
pods.append(Container.from_kubernetes_get_dict(pod_desc))
if describe:
return pods
else:
......
......@@ -53,8 +53,7 @@ docker exec mysql /usr/bin/mysql -N -h127.0.0.1 -uroot -pmysuperpw -e "\
CREATE TABLE IF NOT EXISTS coda_test.my_table(id INT AUTO_INCREMENT, firstname VARCHAR(32), PRIMARY KEY (id)); \
INSERT INTO coda_test.my_table(firstname) VALUES ('Anna'); \
INSERT INTO coda_test.my_table(firstname) VALUES ('Thomas'); \
commit;\
"
commit;"
```
### Backup
......
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