-
Notifications
You must be signed in to change notification settings - Fork 83
feat(clp-package)!: Add support for multiple database user credentials; Use separate root database credentials. #1655
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
cce6146
fc7056f
0f88d3e
5cf882d
9c4aad6
8deda32
8715e9d
d9a0983
a5de1a3
0f70670
04f1538
666d570
37f760e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ | |
| CLP_DB_USER_ENV_VAR_NAME, | ||
| CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, | ||
| CLP_DEFAULT_DATASET_NAME, | ||
| ClpDbUserType, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial CLP credential usage is correct; consider a shared helper for DB env construction Using Given the identical pattern now exists in multiple wrappers ( Also applies to: 256-260 🤖 Prompt for AI Agents |
||
| StorageEngine, | ||
| StorageType, | ||
| ) | ||
|
|
@@ -252,9 +253,10 @@ def main(argv): | |
| logger.error("No filesystem paths given for compression.") | ||
| return -1 | ||
|
|
||
| credentials = clp_config.database.credentials | ||
| extra_env_vars = { | ||
| CLP_DB_USER_ENV_VAR_NAME: clp_config.database.username, | ||
| CLP_DB_PASS_ENV_VAR_NAME: clp_config.database.password, | ||
| CLP_DB_PASS_ENV_VAR_NAME: credentials[ClpDbUserType.CLP].password, | ||
| CLP_DB_USER_ENV_VAR_NAME: credentials[ClpDbUserType.CLP].username, | ||
| } | ||
| container_start_cmd = generate_container_start_cmd( | ||
| container_name, necessary_mounts, clp_config.container_image_ref, extra_env_vars | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,6 +69,8 @@ | |
| CLP_VERSION_FILE_PATH = pathlib.Path("VERSION") | ||
|
|
||
| # Environment variable names | ||
| CLP_DB_ROOT_USER_ENV_VAR_NAME = "CLP_DB_ROOT_USER" | ||
| CLP_DB_ROOT_PASS_ENV_VAR_NAME = "CLP_DB_ROOT_PASS" | ||
| CLP_DB_USER_ENV_VAR_NAME = "CLP_DB_USER" | ||
| CLP_DB_PASS_ENV_VAR_NAME = "CLP_DB_PASS" | ||
| CLP_QUEUE_USER_ENV_VAR_NAME = "CLP_QUEUE_USER" | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
@@ -171,6 +173,16 @@ def validate_query_engine_package_compatibility(self): | |
| return self | ||
|
|
||
|
|
||
| class ClpDbUserType(KebabCaseStrEnum): | ||
Eden-D-Zhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| CLP = auto() | ||
| ROOT = auto() | ||
|
|
||
|
|
||
| class DbUserCredentials(BaseModel): | ||
Eden-D-Zhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| username: NonEmptyStr | None = None | ||
| password: NonEmptyStr | None = None | ||
|
|
||
|
|
||
| class Database(BaseModel): | ||
| DEFAULT_PORT: ClassVar[int] = 3306 | ||
|
|
||
|
|
@@ -182,15 +194,24 @@ class Database(BaseModel): | |
| auto_commit: bool = False | ||
| compress: bool = True | ||
|
|
||
| username: NonEmptyStr | None = None | ||
| password: NonEmptyStr | None = None | ||
| credentials: dict[ClpDbUserType, DbUserCredentials] = { | ||
| ClpDbUserType.CLP: DbUserCredentials(), | ||
| ClpDbUserType.ROOT: DbUserCredentials(), | ||
| } | ||
|
|
||
| def ensure_credentials_loaded(self): | ||
| if self.username is None or self.password is None: | ||
| def ensure_credentials_loaded(self, user_type: ClpDbUserType): | ||
Eden-D-Zhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if ( | ||
| self.credentials[user_type].username is None | ||
| or self.credentials[user_type].password is None | ||
| ): | ||
| raise ValueError("Credentials not loaded.") | ||
Eden-D-Zhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| def get_mysql_connection_params(self, disable_localhost_socket_connection: bool = False): | ||
| self.ensure_credentials_loaded() | ||
| def get_mysql_connection_params( | ||
| self, | ||
| disable_localhost_socket_connection: bool = False, | ||
| user_type: ClpDbUserType = ClpDbUserType.CLP, | ||
| ): | ||
Eden-D-Zhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| self.ensure_credentials_loaded(user_type) | ||
|
|
||
| host = self.host | ||
| if disable_localhost_socket_connection and "localhost" == self.host: | ||
|
|
@@ -200,8 +221,8 @@ def get_mysql_connection_params(self, disable_localhost_socket_connection: bool | |
| connection_params = { | ||
| "host": host, | ||
| "port": self.port, | ||
| "user": self.username, | ||
| "password": self.password, | ||
| "user": self.credentials[user_type].username, | ||
| "password": self.credentials[user_type].password, | ||
| "database": self.name, | ||
| "compress": self.compress, | ||
| "autocommit": self.auto_commit, | ||
|
|
@@ -210,51 +231,74 @@ def get_mysql_connection_params(self, disable_localhost_socket_connection: bool | |
| connection_params["ssl_cert"] = self.ssl_cert | ||
| return connection_params | ||
|
|
||
| def get_clp_connection_params_and_type(self, disable_localhost_socket_connection: bool = False): | ||
| self.ensure_credentials_loaded() | ||
| def get_clp_connection_params_and_type( | ||
| self, | ||
| disable_localhost_socket_connection: bool = False, | ||
| user_type: ClpDbUserType = ClpDbUserType.CLP, | ||
| ): | ||
Eden-D-Zhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| self.ensure_credentials_loaded(user_type) | ||
|
|
||
| host = self.host | ||
| if disable_localhost_socket_connection and "localhost" == self.host: | ||
| host = "127.0.0.1" | ||
|
|
||
| connection_params_and_type = { | ||
| return { | ||
Eden-D-Zhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # NOTE: clp-core does not distinguish between mysql and mariadb | ||
| "type": DatabaseEngine.MYSQL.value, | ||
| "host": host, | ||
| "port": self.port, | ||
| "username": self.username, | ||
| "password": self.password, | ||
| "name": self.name, | ||
| "table_prefix": CLP_METADATA_TABLE_PREFIX, | ||
| "credentials": {user_type: self.credentials[user_type].model_dump()}, | ||
Eden-D-Zhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "database": self.name, | ||
Eden-D-Zhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "compress": self.compress, | ||
| "autocommit": self.auto_commit, | ||
| "name": self.name, | ||
| "type": DatabaseEngine.MYSQL.value, | ||
| "table_prefix": CLP_METADATA_TABLE_PREFIX, | ||
| } | ||
| if self.ssl_cert: | ||
| connection_params_and_type["ssl_cert"] = self.ssl_cert | ||
| return connection_params_and_type | ||
|
|
||
| def dump_to_primitive_dict(self): | ||
Eden-D-Zhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| d = self.model_dump(exclude={"username", "password"}) | ||
| d = self.model_dump(exclude={"credentials"}) | ||
| return d | ||
Eden-D-Zhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| def load_credentials_from_file(self, credentials_file_path: pathlib.Path): | ||
Eden-D-Zhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| config = read_yaml_config_file(credentials_file_path) | ||
| if config is None: | ||
| raise ValueError(f"Credentials file '{credentials_file_path}' is empty.") | ||
| try: | ||
| self.username = get_config_value(config, f"{DB_COMPONENT_NAME}.username") | ||
| self.password = get_config_value(config, f"{DB_COMPONENT_NAME}.password") | ||
| self.credentials[ClpDbUserType.CLP].username = get_config_value( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. unrelated to the PR - using the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. briefly discussed offline - the @coderabbitai create an issue to track |
||
| config, f"{DB_COMPONENT_NAME}.username" | ||
| ) | ||
| self.credentials[ClpDbUserType.CLP].password = get_config_value( | ||
| config, f"{DB_COMPONENT_NAME}.password" | ||
| ) | ||
| self.credentials[ClpDbUserType.ROOT].username = get_config_value( | ||
| config, f"{DB_COMPONENT_NAME}.root_username" | ||
| ) | ||
| self.credentials[ClpDbUserType.ROOT].password = get_config_value( | ||
| config, f"{DB_COMPONENT_NAME}.root_password" | ||
| ) | ||
| except KeyError as ex: | ||
| raise ValueError( | ||
| f"Credentials file '{credentials_file_path}' does not contain key '{ex}'." | ||
| ) | ||
|
|
||
| def load_credentials_from_env(self): | ||
| def load_credentials_from_env(self, user_type: ClpDbUserType = ClpDbUserType.CLP): | ||
| """ | ||
| :raise ValueError: if any expected environment variable is not set. | ||
| Loads database credentials from environment variables. | ||
|
|
||
| :param user_type: User type whose credentials are to be loaded. | ||
|
|
||
| :raise ValueError: If any expected environment variable is not set. | ||
Eden-D-Zhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """ | ||
| self.username = _get_env_var(CLP_DB_USER_ENV_VAR_NAME) | ||
| self.password = _get_env_var(CLP_DB_PASS_ENV_VAR_NAME) | ||
| match user_type: | ||
| case ClpDbUserType.CLP: | ||
| user_env_var = CLP_DB_USER_ENV_VAR_NAME | ||
| pass_env_var = CLP_DB_PASS_ENV_VAR_NAME | ||
| case ClpDbUserType.ROOT: | ||
| user_env_var = CLP_DB_ROOT_USER_ENV_VAR_NAME | ||
| pass_env_var = CLP_DB_ROOT_PASS_ENV_VAR_NAME | ||
Eden-D-Zhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| self.credentials[user_type].username = _get_env_var(user_env_var) | ||
| self.credentials[user_type].password = _get_env_var(pass_env_var) | ||
|
|
||
| def transform_for_container(self): | ||
| self.host = DB_COMPONENT_NAME | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.