1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-07-29 08:21:15 +03:00

feat(cmapi): MCOL-5019: review fixes.

[fix] CEJPasswordHandler class methods to use directory for cskeys file
[fix] CEJPasswordHandler.encrypt_password to return password in hex format
[fix] CEJPasswordHandler key_length
[fix] CEJPasswordHandler os.urandom call typo
[upd] mcs cli README.md and man page
[upd] mcs cli README_DEV.md
[fix] mcs_cluster_tool/decorators.py to handle typer.Exit exception
[add] various docstrings
This commit is contained in:
mariadb-AlanMologorsky
2025-03-13 01:45:42 +03:00
committed by Alan Mologorsky
parent 215e4eea4d
commit aa57a7684c
8 changed files with 248 additions and 60 deletions

View File

@ -18,6 +18,8 @@ $ mcs [OPTIONS] COMMAND [ARGS]...
* `dbrm_backup`: Columnstore DBRM Backup.
* `restore`: Restore Columnstore (and/or MariaDB) data.
* `dbrm_restore`: Restore Columnstore DBRM data.
* `cskeys`: Generates a random AES encryption key and init vector and writes them to disk.
* `cspasswd`: Encrypt a Columnstore plaintext password using the encryption key in the key file.
* `help-all`: Show help for all commands in man page style.
* `status`: Get status information.
* `stop`: Stop the Columnstore cluster.
@ -162,6 +164,50 @@ $ mcs dbrm_restore [OPTIONS]
* `-li, --list`: List backups.
* `--help`: Show this message and exit.
## `mcs cskeys`
This utility generates a random AES encryption key and init vector
and writes them to disk. The data is written to the file '.secrets',
in the specified directory. The key and init vector are used by
the utility 'cspasswd' to encrypt passwords used in Columnstore
configuration files, as well as by Columnstore itself to decrypt the
passwords.
WARNING: Re-creating the file invalidates all existing encrypted
passwords in the configuration files.
**Usage**:
```console
$ mcs cskeys [OPTIONS] [DIRECTORY]
```
**Arguments**:
* `[DIRECTORY]`: The directory where to store the file in. [default: /var/lib/columnstore]
**Options**:
* `-u, --user TEXT`: Designate the owner of the generated file. [default: mysql]
* `--help`: Show this message and exit.
## `mcs cspasswd`
Encrypt a Columnstore plaintext password using the encryption key in
the key file.
**Usage**:
```console
$ mcs cspasswd [OPTIONS]
```
**Options**:
* `--password TEXT`: Password to encrypt/decrypt [required]
* `--decrypt`: Decrypt an encrypted password instead.
* `--help`: Show this message and exit.
## `mcs help-all`
Show help for all commands in man page style.

View File

@ -7,6 +7,14 @@
```bash
typer mcs_cluster_tool/__main__.py utils docs --name mcs --output README.md
```
Optionally could be generated from installed package.
```bash
PYTHONPATH="/usr/share/columnstore/cmapi:/usr/share/columnstore/cmapi/deps" /usr/share/columnstore/cmapi/python/bin/python3 -m typer /usr/share/columnstore/cmapi/mcs_cluster_tool/__main__.py utils docs --name mcs --output ~/README.md
```
- dependencies for gem build (RHEL example)
```bash
sudo dnf install make gcc redhat-rpm-config -y
```
- install `md2man` (for now it's the only one tool that make convertation without any issues)
```bash
sudo yum install -y ruby ruby-devel
@ -14,6 +22,6 @@
```
- convert to perfect `.roff` file (`man` page)
```bash
md2man README.md > mcs.1
md2man-roff README.md > mcs.1
```
- enjoy =)

View File

@ -36,9 +36,16 @@ app.command(
app.command(
'dbrm_restore', rich_help_panel='Tools commands'
)(restore_commands.dbrm_restore)
app.command('cskeys', rich_help_panel='Tools commands')(tools_commands.cskeys)
app.command(
'cspasswd', rich_help_panel='Tools commands'
'cskeys', rich_help_panel='Tools commands',
short_help=(
'Generates a random AES encryption key and init vector and writes '
'them to disk.'
)
)(tools_commands.cskeys)
app.command(
'cspasswd', rich_help_panel='Tools commands',
short_help='Encrypt a Columnstore plaintext password.'
)(tools_commands.cspasswd)

View File

@ -25,11 +25,16 @@ def handle_output(func):
except typer.BadParameter as err:
logger.error('Bad command line parameter.')
raise err
except typer.Exit as err: # if some command used typer.Exit
#TODO: think about universal protocol to return json data and
# plain text results.
return_code = err.exit_code
except Exception:
logger.error(
'Undefined error during command execution',
exc_info=True
)
typer.echo('Unknown error, check the log file.', err=True)
raise typer.Exit(return_code)
return wrapper

View File

@ -27,6 +27,10 @@ $ mcs [OPTIONS] COMMAND [ARGS]...
.IP \(bu 2
\fB\fCdbrm_restore\fR: Restore Columnstore DBRM data.
.IP \(bu 2
\fB\fCcskeys\fR: Generates a random AES encryption key and init vector and writes them to disk.
.IP \(bu 2
\fB\fCcspasswd\fR: Encrypt a Columnstore plaintext password using the encryption key in the key file.
.IP \(bu 2
\fB\fChelp\-all\fR: Show help for all commands in man page style.
.IP \(bu 2
\fB\fCstatus\fR: Get status information.
@ -252,6 +256,61 @@ $ mcs dbrm_restore [OPTIONS]
.IP \(bu 2
\fB\fC\-\-help\fR: Show this message and exit.
.RE
.SH \fB\fCmcs cskeys\fR
.PP
This utility generates a random AES encryption key and init vector
and writes them to disk. The data is written to the file \[aq]\&.secrets\[aq],
in the specified directory. The key and init vector are used by
the utility \[aq]cspasswd\[aq] to encrypt passwords used in Columnstore
configuration files, as well as by Columnstore itself to decrypt the
passwords.
.PP
WARNING: Re\-creating the file invalidates all existing encrypted
passwords in the configuration files.
.PP
\fBUsage\fP:
.PP
.RS
.nf
$ mcs cskeys [OPTIONS] [DIRECTORY]
.fi
.RE
.PP
\fBArguments\fP:
.RS
.IP \(bu 2
\fB\fC[DIRECTORY]\fR: The directory where to store the file in. [default: /var/lib/columnstore]
.RE
.PP
\fBOptions\fP:
.RS
.IP \(bu 2
\fB\fC\-u, \-\-user TEXT\fR: Designate the owner of the generated file. [default: mysql]
.IP \(bu 2
\fB\fC\-\-help\fR: Show this message and exit.
.RE
.SH \fB\fCmcs cspasswd\fR
.PP
Encrypt a Columnstore plaintext password using the encryption key in
the key file.
.PP
\fBUsage\fP:
.PP
.RS
.nf
$ mcs cspasswd [OPTIONS]
.fi
.RE
.PP
\fBOptions\fP:
.RS
.IP \(bu 2
\fB\fC\-\-password TEXT\fR: Password to encrypt/decrypt [required]
.IP \(bu 2
\fB\fC\-\-decrypt\fR: Decrypt an encrypted password instead.
.IP \(bu 2
\fB\fC\-\-help\fR: Show this message and exit.
.RE
.SH \fB\fCmcs help\-all\fR
.PP
Show help for all commands in man page style.

View File

@ -5,7 +5,9 @@ import typer
from typing_extensions import Annotated
from cmapi_server.constants import MCS_SECRETS_FILE_PATH
from cmapi_server.constants import (
MCS_DATA_PATH, MCS_SECRETS_FILENAME
)
from cmapi_server.exceptions import CEJError
from cmapi_server.handlers.cej import CEJPasswordHandler
from mcs_cluster_tool.decorators import handle_output
@ -18,22 +20,33 @@ logger = logging.getLogger('mcs_cli')
@handle_output
def cskeys(
filepath: Annotated[
user: Annotated[
str,
typer.Option(
'-f', '--filepath',
help='Path to the output file',
)
] = MCS_SECRETS_FILE_PATH,
username: Annotated[
str,
typer.Option(
'-u', '--username',
help='Username for the key',
'-u', '--user',
help='Designate the owner of the generated file.',
)
] = 'mysql',
directory: Annotated[
str,
typer.Argument(
help='The directory where to store the file in.',
)
] = MCS_DATA_PATH
):
if CEJPasswordHandler().secretsfile_exists():
"""
This utility generates a random AES encryption key and init vector
and writes them to disk. The data is written to the file '.secrets',
in the specified directory. The key and init vector are used by
the utility 'cspasswd' to encrypt passwords used in Columnstore
configuration files, as well as by Columnstore itself to decrypt the
passwords.
WARNING: Re-creating the file invalidates all existing encrypted
passwords in the configuration files.
"""
filepath = os.path.join(directory, MCS_SECRETS_FILENAME)
if CEJPasswordHandler().secretsfile_exists(directory=directory):
typer.echo(
(
f'Secrets file "{filepath}" already exists. '
@ -44,14 +57,18 @@ def cskeys(
raise typer.Exit(code=1)
elif not os.path.exists(os.path.dirname(filepath)):
typer.echo(
f'Directory "{os.path.dirname(filepath)}" does not exist.',
f'Directory "{directory}" does not exist.',
color='red'
)
raise typer.Exit(code=1)
new_secrets_data = CEJPasswordHandler().generate_secrets_data()
try:
CEJPasswordHandler().save_secrets(new_secrets_data, owner=username)
CEJPasswordHandler().save_secrets(
new_secrets_data, owner=user, directory=directory
)
typer.echo(f'Permissions of "{filepath}" set to owner:read.')
typer.echo(f'Ownership of "{filepath}" given to {user}.')
except CEJError as cej_error:
typer.echo(cej_error.message, color='red')
raise typer.Exit(code=2)
@ -71,10 +88,14 @@ def cspasswd(
bool,
typer.Option(
'--decrypt',
help='Decrypt the provided password',
help='Decrypt an encrypted password instead.',
)
] = False
):
"""
Encrypt a Columnstore plaintext password using the encryption key in
the key file.
"""
if decrypt:
try:
decrypted_password = CEJPasswordHandler().decrypt_password(