mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-04-18 21:44:02 +03:00
feat(cmapi, mcs): MCOL-5941 Improve mcs cli backup\restore wrapper.
* fix(mcs, wrapper): default is None for --backup-location, --backup-destination, --storage, --parallel, --highavilability, --skip-save-brm, --skip-polls, --skip-locks, --skip-mariadb-backup, --skip-bucket-data, --name-backup, --quiet, --no-verify-ssl, --poll-interval, --poll-max-wait, --retention-days * fix(mcs, helpers): cook_sh_arg parser function now detects None as a value * docs(mcs, wrapper): --parralel arg help message was edited to simpler
This commit is contained in:
parent
a16fbd137b
commit
9bae93c4b6
@ -2,6 +2,7 @@
|
||||
import logging
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
import typer
|
||||
from typing_extensions import Annotated
|
||||
@ -20,7 +21,7 @@ logger = logging.getLogger('mcs_cli')
|
||||
@handle_output
|
||||
def backup(
|
||||
bl: Annotated[
|
||||
str,
|
||||
Optional[str],
|
||||
typer.Option(
|
||||
'-bl', '--backup-location',
|
||||
help=(
|
||||
@ -28,11 +29,12 @@ def backup(
|
||||
'Consider write permissions of the scp user and the user running this script.\n'
|
||||
'Mariadb-backup will use this location as a tmp dir for S3 and remote backups temporarily.\n'
|
||||
'Example: /mnt/backups/'
|
||||
)
|
||||
),
|
||||
show_default=False
|
||||
)
|
||||
] = '/tmp/backups/',
|
||||
] = None,
|
||||
bd: Annotated[
|
||||
str,
|
||||
Optional[str],
|
||||
typer.Option(
|
||||
'-bd', '--backup-destination',
|
||||
help=(
|
||||
@ -40,9 +42,10 @@ def backup(
|
||||
'script is running on or another server - if Remote you need '
|
||||
'to setup scp='
|
||||
'Options: "Local" or "Remote"'
|
||||
)
|
||||
),
|
||||
show_default=False
|
||||
)
|
||||
] = 'Local',
|
||||
] = None,
|
||||
scp: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
@ -77,16 +80,17 @@ def backup(
|
||||
)
|
||||
] = '',
|
||||
s: Annotated[
|
||||
str,
|
||||
Optional[str],
|
||||
typer.Option(
|
||||
'-s', '--storage',
|
||||
help=(
|
||||
'What storage topogoly is being used by Columnstore - found '
|
||||
'in /etc/columnstore/storagemanager.cnf.\n'
|
||||
'Options: "LocalStorage" or "S3"'
|
||||
)
|
||||
),
|
||||
show_default=False
|
||||
)
|
||||
] = 'LocalStorage',
|
||||
] = None,
|
||||
i: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
@ -101,19 +105,18 @@ def backup(
|
||||
)
|
||||
] = '',
|
||||
P: Annotated[
|
||||
int,
|
||||
Optional[int],
|
||||
typer.Option(
|
||||
'-P', '--parallel',
|
||||
help=(
|
||||
'Determines if columnstore data directories will have '
|
||||
'multiple rsync running at the same time for different '
|
||||
'subfolders to parallelize writes. '
|
||||
'Number of parallel rsync/compression threads to run. '
|
||||
'Ignored if "-c/--compress" argument not set.'
|
||||
)
|
||||
),
|
||||
show_default=False
|
||||
)
|
||||
] = 4,
|
||||
] = None,
|
||||
ha: Annotated[
|
||||
bool,
|
||||
Optional[bool],
|
||||
typer.Option(
|
||||
'-ha/-no-ha', '--highavilability/--no-highavilability',
|
||||
help=(
|
||||
@ -121,9 +124,10 @@ def backup(
|
||||
'to see all data\n'
|
||||
' HA LocalStorage ( /var/lib/columnstore/dataX/ )\n'
|
||||
' HA S3 ( /var/lib/columnstore/storagemanager/ )'
|
||||
)
|
||||
),
|
||||
show_default=False
|
||||
)
|
||||
] = False,
|
||||
] = None,
|
||||
f: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
@ -136,53 +140,59 @@ def backup(
|
||||
)
|
||||
] = '',
|
||||
sbrm: Annotated[
|
||||
bool,
|
||||
Optional[bool],
|
||||
typer.Option(
|
||||
'-sbrm/-no-sbrm', '--skip-save-brm/--no-skip-save-brm',
|
||||
help=(
|
||||
'Skip saving brm prior to running a backup - '
|
||||
'ideal for dirty backups.'
|
||||
)
|
||||
),
|
||||
show_default=False
|
||||
)
|
||||
] = False,
|
||||
] = None,
|
||||
spoll: Annotated[
|
||||
bool,
|
||||
Optional[bool],
|
||||
typer.Option(
|
||||
'-spoll/-no-spoll', '--skip-polls/--no-skip-polls',
|
||||
help='Skip sql checks confirming no write/cpimports running.'
|
||||
help='Skip sql checks confirming no write/cpimports running.',
|
||||
show_default=False
|
||||
)
|
||||
] = False,
|
||||
] = None,
|
||||
slock: Annotated[
|
||||
bool,
|
||||
Optional[bool],
|
||||
typer.Option(
|
||||
'-slock/-no-slock', '--skip-locks/--no-skip-locks',
|
||||
help='Skip issuing write locks - ideal for dirty backups.'
|
||||
help='Skip issuing write locks - ideal for dirty backups.',
|
||||
show_default=False
|
||||
)
|
||||
] = False,
|
||||
] = None,
|
||||
smdb: Annotated[
|
||||
bool,
|
||||
Optional[bool],
|
||||
typer.Option(
|
||||
'-smdb/-no-smdb', '--skip-mariadb-backup/--no-skip-mariadb-backup',
|
||||
help=(
|
||||
'Skip running a mariadb-backup for innodb data - ideal for '
|
||||
'incremental dirty backups.'
|
||||
)
|
||||
),
|
||||
show_default=False
|
||||
)
|
||||
] = False,
|
||||
] = None,
|
||||
sb: Annotated[
|
||||
bool,
|
||||
Optional[bool],
|
||||
typer.Option(
|
||||
'-sb/-no-sb', '--skip-bucket-data/--no-skip-bucket-data',
|
||||
help='Skip taking a copy of the columnstore data in the bucket.'
|
||||
help='Skip taking a copy of the columnstore data in the bucket.',
|
||||
show_default=False
|
||||
)
|
||||
] = False,
|
||||
] = None,
|
||||
nb: Annotated[
|
||||
str,
|
||||
Optional[str],
|
||||
typer.Option(
|
||||
'-nb', '--name-backup',
|
||||
help='Define the name of the backup - default: $(date +%m-%d-%Y)'
|
||||
help='Define the name of the backup - default: $(date +%m-%d-%Y)',
|
||||
show_default=False
|
||||
)
|
||||
] = datetime.now().strftime('%m-%d-%Y'),
|
||||
] = None,
|
||||
m: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
@ -205,49 +215,54 @@ def backup(
|
||||
)
|
||||
] = '',
|
||||
q: Annotated[
|
||||
bool,
|
||||
Optional[bool],
|
||||
typer.Option(
|
||||
'-q/-no-q', '--quiet/--no-quiet',
|
||||
help='Silence verbose copy command outputs.'
|
||||
help='Silence verbose copy command outputs.',
|
||||
show_default=False
|
||||
)
|
||||
] = False,
|
||||
] = None,
|
||||
nv_ssl: Annotated[
|
||||
bool,
|
||||
Optional[bool],
|
||||
typer.Option(
|
||||
'-nv-ssl/-v-ssl','--no-verify-ssl/--verify-ssl',
|
||||
help='Skips verifying ssl certs, useful for onpremise s3 storage.'
|
||||
help='Skips verifying ssl certs, useful for onpremise s3 storage.',
|
||||
show_default=False
|
||||
)
|
||||
] = False,
|
||||
] = None,
|
||||
pi: Annotated[
|
||||
int,
|
||||
Optional[int],
|
||||
typer.Option(
|
||||
'-pi', '--poll-interval',
|
||||
help=(
|
||||
'Number of seconds between poll checks for active writes & '
|
||||
'cpimports.'
|
||||
)
|
||||
),
|
||||
show_default=False
|
||||
)
|
||||
] = 5,
|
||||
] = None,
|
||||
pmw: Annotated[
|
||||
int,
|
||||
Optional[int],
|
||||
typer.Option(
|
||||
'-pmw', '--poll-max-wait',
|
||||
help=(
|
||||
'Max number of minutes for polling checks for writes to wait '
|
||||
'before exiting as a failed backup attempt.'
|
||||
)
|
||||
),
|
||||
show_default=False
|
||||
)
|
||||
] = 60,
|
||||
] = None,
|
||||
r: Annotated[
|
||||
int,
|
||||
Optional[int],
|
||||
typer.Option(
|
||||
'-r', '--retention-days',
|
||||
help=(
|
||||
'Retain backups created within the last X days, '
|
||||
'default 0 == keep all backups.'
|
||||
)
|
||||
),
|
||||
show_default=False
|
||||
)
|
||||
] = 0,
|
||||
] = None,
|
||||
aro: Annotated[
|
||||
bool,
|
||||
typer.Option(
|
||||
|
@ -1,22 +1,27 @@
|
||||
"""Module with helper functions for mcs cli tool."""
|
||||
from typing import Union
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
def cook_sh_arg(arg_name: str, value:Union[str, int, bool]) -> str:
|
||||
def cook_sh_arg(arg_name: str, value: Union[str, int, bool]) -> Optional[str]:
|
||||
"""Convert argument and and value from function locals to bash argument.
|
||||
|
||||
:param arg_name: function argument name
|
||||
:type arg_name: str
|
||||
:param value: function argument value
|
||||
:type value: Union[str, int, bool]
|
||||
:return: bash argument string
|
||||
:rtype: str
|
||||
:return: bash argument string or None
|
||||
:rtype: Optional[str]
|
||||
"""
|
||||
# skip "arguments" list and Typer ctx variables from local scope
|
||||
if arg_name in ('arguments', 'ctx'):
|
||||
return None
|
||||
# skip args that have empty string as value
|
||||
if value == '':
|
||||
# skip args that have empty string or None as value
|
||||
# Condition below could be "not value", but I prefer to be explicit
|
||||
# and check for empty string and None to show that it's different cases:
|
||||
# empty string means that user passed empty string as value
|
||||
# and None means that user didn't pass anything and our internal None
|
||||
# applies
|
||||
if value == '' or value is None:
|
||||
return None
|
||||
if '_' in arg_name:
|
||||
arg_name = arg_name.replace('_', '-')
|
||||
|
Loading…
x
Reference in New Issue
Block a user