已开启
bugfux #202
zzh创建于 2025年7月14日
bugfux #202
已开启
共 10 个文件变更+82-38
| @@ -13,7 +13,9 @@ | |||
| 13 | """Command Line Interface""" | 13 | """Command Line Interface""" |
| 14 | 14 | ||
| 15 | import argparse | 15 | import argparse |
| 16 | +import functools | ||
| 16 | import os | 17 | import os |
| 18 | +import psycopg2 | ||
| 17 | 19 | ||
| 18 | from dbmind import components as components_module | 20 | from dbmind import components as components_module |
| 19 | from dbmind.common.exceptions import SetupError, ConfigSettingError | 21 | from dbmind.common.exceptions import SetupError, ConfigSettingError |
| @@ -28,6 +30,9 @@ from . import edbmind | |||
| 28 | from . import setup | 30 | from . import setup |
| 29 | 31 | ||
| 30 | 32 | ||
| 33 | +psycopg2.connect = functools.partial(psycopg2.connect, sslmode='prefer') | ||
| 34 | + | ||
| 35 | + | ||
| 31 | def build_parser(): | 36 | def build_parser(): |
| 32 | actions = ['setup', 'start', 'stop', 'restart', 'reload'] | 37 | actions = ['setup', 'start', 'stop', 'restart', 'reload'] |
| 33 | # Create the top-level parser to parse the common action. | 38 | # Create the top-level parser to parse the common action. |
| @@ -17,12 +17,12 @@ from dbmind import constants | |||
| 17 | from dbmind.cmd.configs.config_constants import ( | 17 | from dbmind.cmd.configs.config_constants import ( |
| 18 | ENCRYPTED_SIGNAL, check_config_validity, NULL_TYPE, IV_TABLE | 18 | ENCRYPTED_SIGNAL, check_config_validity, NULL_TYPE, IV_TABLE |
| 19 | ) | 19 | ) |
| 20 | -from dbmind.cmd.configs.configurators import ReadonlyConfig, UpdateConfig | 20 | +from dbmind.cmd.configs.configurators import ReadonlyConfig, UpdateConfig, create_dynamic_configs, \ |
| 21 | -from dbmind.common import security, utils | 21 | + get_config_security_keys |
| 22 | +from dbmind.common import security | ||
| 22 | from dbmind.common.exceptions import ConfigSettingError | 23 | from dbmind.common.exceptions import ConfigSettingError |
| 23 | from dbmind.common.utils.cli import write_to_terminal | 24 | from dbmind.common.utils.cli import write_to_terminal |
| 24 | from dbmind.metadatabase.dao.dynamic_config import dynamic_config_get, dynamic_config_set | 25 | from dbmind.metadatabase.dao.dynamic_config import dynamic_config_get, dynamic_config_set |
| 25 | -from dbmind.metadatabase.ddl import create_dynamic_config_schema | ||
| 26 | 26 | ||
| 27 | 27 | ||
| 28 | def load_sys_configs(confile): | 28 | def load_sys_configs(confile): |
| @@ -48,8 +48,7 @@ def set_config_parameter(confpath, section: str, option: str, value: str): | |||
| 48 | if 'password' in option: | 48 | if 'password' in option: |
| 49 | # dynamic_config_xxx searches file from current working directory. | 49 | # dynamic_config_xxx searches file from current working directory. |
| 50 | os.chdir(confpath) | 50 | os.chdir(confpath) |
| 51 | - s1 = dynamic_config_get(IV_TABLE, 'cipher_s1') | 51 | + s1, s2 = get_config_security_keys(os.path.join(confpath, constants.CIPHER_S1)) |
| 52 | - s2 = dynamic_config_get(IV_TABLE, 'cipher_s2') | ||
| 53 | # Every time a new password is generated, update the IV. | 52 | # Every time a new password is generated, update the IV. |
| 54 | iv = security.generate_an_iv() | 53 | iv = security.generate_an_iv() |
| 55 | dynamic_config_set(IV_TABLE, '%s-%s' % (section, option), iv) | 54 | dynamic_config_set(IV_TABLE, '%s-%s' % (section, option), iv) |
| @@ -74,26 +73,6 @@ def set_config_parameter(confpath, section: str, option: str, value: str): | |||
| 74 | write_to_terminal('Success to modify parameter %s-%s.' % (section, option), color='green') | 73 | write_to_terminal('Success to modify parameter %s-%s.' % (section, option), color='green') |
| 75 | 74 | ||
| 76 | 75 | ||
| 77 | -def create_dynamic_configs(): | ||
| 78 | - """Create dynamic configuration schema and | ||
| 79 | - generate security keys.""" | ||
| 80 | - utils.cli.write_to_terminal( | ||
| 81 | - 'Starting to generate a dynamic config file...', | ||
| 82 | - color='green') | ||
| 83 | - create_dynamic_config_schema() | ||
| 84 | - s1_ = security.safe_random_string(16) | ||
| 85 | - s2_ = security.safe_random_string(16) | ||
| 86 | - dynamic_config_set(IV_TABLE, 'cipher_s1', s1_) | ||
| 87 | - dynamic_config_set(IV_TABLE, 'cipher_s2', s2_) | ||
| 88 | - return s1_, s2_ | ||
| 89 | - | ||
| 90 | - | ||
| 91 | -def get_config_security_keys(): | ||
| 92 | - s1 = dynamic_config_get(IV_TABLE, 'cipher_s1') | ||
| 93 | - s2 = dynamic_config_get(IV_TABLE, 'cipher_s2') | ||
| 94 | - return s1, s2 | ||
| 95 | - | ||
| 96 | - | ||
| 97 | def config_standardize_null_value(value): | 76 | def config_standardize_null_value(value): |
| 98 | # If not set default value, | 77 | # If not set default value, |
| 99 | # the default value is null. | 78 | # the default value is null. |
| @@ -19,7 +19,8 @@ from dbmind.cmd.configs.config_constants import ( | |||
| 19 | SKIP_LIST, NULL_TYPE, ENCRYPTED_SIGNAL, | 19 | SKIP_LIST, NULL_TYPE, ENCRYPTED_SIGNAL, |
| 20 | DBMIND_CONF_HEADER, IV_TABLE, | 20 | DBMIND_CONF_HEADER, IV_TABLE, |
| 21 | check_config_validity) | 21 | check_config_validity) |
| 22 | -from dbmind.common import security | 22 | +from dbmind import constants |
| 23 | +from dbmind.common import security, utils | ||
| 23 | from dbmind.common.exceptions import ( | 24 | from dbmind.common.exceptions import ( |
| 24 | InvalidCredentialException, ConfigSettingError) | 25 | InvalidCredentialException, ConfigSettingError) |
| 25 | from dbmind.common.utils import (ExceptionCatcher, | 26 | from dbmind.common.utils import (ExceptionCatcher, |
| @@ -29,6 +30,7 @@ from dbmind.metadatabase.dao.dynamic_config import ( | |||
| 29 | dynamic_configs_list, dynamic_category_configs_get) | 30 | dynamic_configs_list, dynamic_category_configs_get) |
| 30 | 31 | ||
| 31 | from .base_configurator import BaseConfig | 32 | from .base_configurator import BaseConfig |
| 33 | +from ...metadatabase.ddl import create_dynamic_config_schema | ||
| 32 | 34 | ||
| 33 | 35 | ||
| 34 | class ReadonlyConfig(BaseConfig): | 36 | class ReadonlyConfig(BaseConfig): |
| @@ -50,6 +52,7 @@ class ReadonlyConfig(BaseConfig): | |||
| 50 | # Otherwise, it will cause the read configuration | 52 | # Otherwise, it will cause the read configuration |
| 51 | # items to be wrong. | 53 | # items to be wrong. |
| 52 | self._configs = ConfigParser(inline_comment_prefixes='#') | 54 | self._configs = ConfigParser(inline_comment_prefixes='#') |
| 55 | + self.conf_dir = os.path.dirname(filepath) | ||
| 53 | with open(file=filepath, mode='r') as fp: | 56 | with open(file=filepath, mode='r') as fp: |
| 54 | self._configs.read_file(fp) | 57 | self._configs.read_file(fp) |
| 55 | 58 | ||
| @@ -76,8 +79,7 @@ class ReadonlyConfig(BaseConfig): | |||
| 76 | if value == NULL_TYPE: | 79 | if value == NULL_TYPE: |
| 77 | value = '' | 80 | value = '' |
| 78 | if 'password' in option and value != '': | 81 | if 'password' in option and value != '': |
| 79 | - s1 = dynamic_config_get(IV_TABLE, 'cipher_s1') | 82 | + s1, s2 = get_config_security_keys(os.path.join(self.conf_dir, constants.CIPHER_S1)) |
| 80 | - s2 = dynamic_config_get(IV_TABLE, 'cipher_s2') | ||
| 81 | iv = dynamic_config_get(IV_TABLE, '%s-%s' % (section, option)) | 83 | iv = dynamic_config_get(IV_TABLE, '%s-%s' % (section, option)) |
| 82 | if value.startswith(ENCRYPTED_SIGNAL) and iv: | 84 | if value.startswith(ENCRYPTED_SIGNAL) and iv: |
| 83 | real_value = value[len(ENCRYPTED_SIGNAL):] | 85 | real_value = value[len(ENCRYPTED_SIGNAL):] |
| @@ -223,3 +225,25 @@ class DynamicConfig: | |||
| 223 | def get_category_values(category): | 225 | def get_category_values(category): |
| 224 | return dynamic_category_configs_get(category) | 226 | return dynamic_category_configs_get(category) |
| 225 | 227 | ||
| 228 | +def create_dynamic_configs(s1_file): | ||
| 229 | + """Create dynamic configuration schema and | ||
| 230 | + generate security keys.""" | ||
| 231 | + utils.cli.write_to_terminal( | ||
| 232 | + 'Starting to generate a dynamic config file...', | ||
| 233 | + color='green') | ||
| 234 | + create_dynamic_config_schema() | ||
| 235 | + s1_ = security.safe_random_string(16) | ||
| 236 | + s2_ = security.safe_random_string(16) | ||
| 237 | + with open(s1_file, 'w') as file_h: | ||
| 238 | + file_h.write(s1_) | ||
| 239 | + dynamic_config_set(IV_TABLE, 'cipher_s2', s2_) | ||
| 240 | + return s1_, s2_ | ||
| 241 | + | ||
| 242 | + | ||
| 243 | +def get_config_security_keys(s1_file): | ||
| 244 | + if os.path.exists(s1_file): | ||
| 245 | + s1 = open(s1_file).read() | ||
| 246 | + else: | ||
| 247 | + s1 = dynamic_config_get(IV_TABLE, 'cipher_s1') | ||
| 248 | + s2 = dynamic_config_get(IV_TABLE, 'cipher_s2') | ||
| 249 | + return s1, s2 | ||
| @@ -12,8 +12,10 @@ | |||
| 12 | # See the Mulan PSL v2 for more details. | 12 | # See the Mulan PSL v2 for more details. |
| 13 | """DBMind common functionality interface""" | 13 | """DBMind common functionality interface""" |
| 14 | 14 | ||
| 15 | +import functools | ||
| 15 | import logging | 16 | import logging |
| 16 | import os | 17 | import os |
| 18 | +import psycopg2 | ||
| 17 | import signal | 19 | import signal |
| 18 | import sys | 20 | import sys |
| 19 | import threading | 21 | import threading |
| @@ -316,6 +318,14 @@ class DBMindMain(Daemon): | |||
| 316 | # Initialize TSDB. | 318 | # Initialize TSDB. |
| 317 | tsdb = init_tsdb_with_config() | 319 | tsdb = init_tsdb_with_config() |
| 318 | 320 | ||
| 321 | + # check sslmode for METADATABASE connection | ||
| 322 | + ssl_mode = global_vars.configs.get('METADATABASE', 'ssl_mode', fallback='prefer') | ||
| 323 | + if ssl_mode not in ['disable', 'prefer', 'verify-ca']: | ||
| 324 | + utils.cli.write_to_terminal(f"Error: ssl_mode only support disable or prefer or verify-ca mode." | ||
| 325 | + f" Please make sure the parameters meet the requirements.") | ||
| 326 | + return | ||
| 327 | + psycopg2.connect = functools.partial(psycopg2.connect, sslmode=ssl_mode) | ||
| 328 | + | ||
| 319 | # Initialize RPC agent. | 329 | # Initialize RPC agent. |
| 320 | init_rpc_with_config(tsdb) | 330 | init_rpc_with_config(tsdb) |
| 321 | for p in utils.split(global_vars.configs.get('AGENT', 'password')): | 331 | for p in utils.split(global_vars.configs.get('AGENT', 'password')): |
| @@ -22,13 +22,15 @@ from dbmind.cmd.configs.config_utils import ( | |||
| 22 | config_set_value_encrypted_flag, | 22 | config_set_value_encrypted_flag, |
| 23 | config_is_encrypted_value, | 23 | config_is_encrypted_value, |
| 24 | config_standardize_null_value, | 24 | config_standardize_null_value, |
| 25 | - get_config_security_keys, | 25 | + set_config_encryption_iv) |
| 26 | - set_config_encryption_iv, | 26 | +from dbmind.cmd.configs.configurators import UpdateConfig, DynamicConfig, GenerationConfig, create_dynamic_configs, \ |
| 27 | - create_dynamic_configs) | 27 | + get_config_security_keys |
| 28 | -from dbmind.cmd.configs.configurators import UpdateConfig, DynamicConfig, GenerationConfig | 28 | +from dbmind.cmd.configs.config_constants import ENCRYPTED_SIGNAL |
| 29 | from dbmind.common import utils, security | 29 | from dbmind.common import utils, security |
| 30 | from dbmind.common.exceptions import SetupError, SQLExecutionError, DuplicateTableError | 30 | from dbmind.common.exceptions import SetupError, SQLExecutionError, DuplicateTableError |
| 31 | +from dbmind.metadatabase.dao.dynamic_config import dynamic_config_get, dynamic_config_set | ||
| 31 | from dbmind.metadatabase.ddl import create_metadatabase_schema, destroy_metadatabase | 32 | from dbmind.metadatabase.ddl import create_metadatabase_schema, destroy_metadatabase |
| 33 | +from dbmind.metadatabase.schema.config_dynamic_params import IV_TABLE | ||
| 32 | 34 | ||
| 33 | 35 | ||
| 34 | def initialize_and_check_config(confpath, interactive=False, quiet=False): | 36 | def initialize_and_check_config(confpath, interactive=False, quiet=False): |
| @@ -43,17 +45,17 @@ def initialize_and_check_config(confpath, interactive=False, quiet=False): | |||
| 43 | 45 | ||
| 44 | if not os.path.exists(dynamic_config_path): | 46 | if not os.path.exists(dynamic_config_path): |
| 45 | # If dynamic config file does not exist, create a new one. | 47 | # If dynamic config file does not exist, create a new one. |
| 46 | - s1, s2 = create_dynamic_configs() | 48 | + s1, s2 = create_dynamic_configs(os.path.join(confpath, constants.CIPHER_S1)) |
| 47 | else: | 49 | else: |
| 48 | # If exists, need not create a new dynamic config file | 50 | # If exists, need not create a new dynamic config file |
| 49 | # and directly load hash key s1 and s2 from it. | 51 | # and directly load hash key s1 and s2 from it. |
| 50 | - s1, s2 = get_config_security_keys() | 52 | + s1, s2 = get_config_security_keys(os.path.join(confpath, constants.CIPHER_S1)) |
| 51 | if not (s1 and s2): | 53 | if not (s1 and s2): |
| 52 | # If s1 or s2 is invalid, it indicates that an broken event may occurred while generating | 54 | # If s1 or s2 is invalid, it indicates that an broken event may occurred while generating |
| 53 | # the dynamic config file. Hence, the whole process of generation is unreliable and we have to | 55 | # the dynamic config file. Hence, the whole process of generation is unreliable and we have to |
| 54 | # generate a new dynamic config file. | 56 | # generate a new dynamic config file. |
| 55 | os.unlink(dynamic_config_path) | 57 | os.unlink(dynamic_config_path) |
| 56 | - s1, s2 = create_dynamic_configs() | 58 | + s1, s2 = create_dynamic_configs(os.path.join(confpath, constants.CIPHER_S1)) |
| 57 | 59 | ||
| 58 | # Check some configurations and encrypt passwords. | 60 | # Check some configurations and encrypt passwords. |
| 59 | with UpdateConfig(dbmind_conf_path) as config: | 61 | with UpdateConfig(dbmind_conf_path) as config: |
| @@ -151,6 +153,16 @@ def setup_directory_interactive(confpath): | |||
| 151 | ) | 153 | ) |
| 152 | utils.base.chmod_r(confpath, 0o700, 0o600) | 154 | utils.base.chmod_r(confpath, 0o700, 0o600) |
| 153 | 155 | ||
| 156 | + os.chdir(confpath) | ||
| 157 | + dynamic_config_path = os.path.join(confpath, constants.DYNAMIC_CONFIG) | ||
| 158 | + if not os.path.exists(dynamic_config_path): | ||
| 159 | + create_dynamic_configs(os.path.join(confpath, constants.CIPHER_S1)) | ||
| 160 | + else: | ||
| 161 | + s1, s2 = get_config_security_keys(os.path.join(confpath, constants.CIPHER_S1)) | ||
| 162 | + if not (s1 and s2): | ||
| 163 | + os.unlink(dynamic_config_path) | ||
| 164 | + create_dynamic_configs(os.path.join(confpath, constants.CIPHER_S1)) | ||
| 165 | + | ||
| 154 | utils.cli.write_to_terminal('Starting to configure...', color='green') | 166 | utils.cli.write_to_terminal('Starting to configure...', color='green') |
| 155 | # Generate an initial configuration file. | 167 | # Generate an initial configuration file. |
| 156 | with GenerationConfig( | 168 | with GenerationConfig( |
| @@ -202,6 +214,16 @@ def setup_directory_interactive(confpath): | |||
| 202 | color='red' | 214 | color='red' |
| 203 | ) | 215 | ) |
| 204 | input_value = '' | 216 | input_value = '' |
| 217 | + if 'password' in option and input_value != default_value: | ||
| 218 | + # dynamic_config_xxx searches file from current working directory. | ||
| 219 | + os.chdir(confpath) | ||
| 220 | + s1, s2 = get_config_security_keys(os.path.join(confpath, constants.CIPHER_S1)) | ||
| 221 | + # Every time a new password is generated, update the IV. | ||
| 222 | + iv = security.generate_an_iv() | ||
| 223 | + dynamic_config_set(IV_TABLE, '%s-%s' % (section, option), iv) | ||
| 224 | + cipher = security.encrypt(s1, s2, iv, input_value) | ||
| 225 | + input_value = ENCRYPTED_SIGNAL + cipher | ||
| 226 | + | ||
| 205 | config.set(section, option, '%s # %s' % ( | 227 | config.set(section, option, '%s # %s' % ( |
| 206 | input_value, inline_comment)) | 228 | input_value, inline_comment)) |
| 207 | except (KeyboardInterrupt, EOFError, ValueError): | 229 | except (KeyboardInterrupt, EOFError, ValueError): |
| @@ -58,7 +58,7 @@ class HttpService: | |||
| 58 | """ | 58 | """ |
| 59 | 59 | ||
| 60 | def __init__(self, name=__name__): | 60 | def __init__(self, name=__name__): |
| 61 | - self.app = FastAPI(title=name) | 61 | + self.app = FastAPI(title=name, openapi_url=None, docs_url=None, redoc_url=None) |
| 62 | self._server = None | 62 | self._server = None |
| 63 | self.static_directory = None | 63 | self.static_directory = None |
| 64 | self.need_to_exit = False | 64 | self.need_to_exit = False |
| @@ -26,8 +26,7 @@ from dbmind.common.utils import dbmind_assert, write_to_terminal | |||
| 26 | 26 | ||
| 27 | _psycopg2_kwargs = dict( | 27 | _psycopg2_kwargs = dict( |
| 28 | options="-c session_timeout=15 -c search_path=public", | 28 | options="-c session_timeout=15 -c search_path=public", |
| 29 | - application_name='DBMind-openGauss-exporter', | 29 | + application_name='DBMind-openGauss-exporter' |
| 30 | - sslmode='disable', | ||
| 31 | ) | 30 | ) |
| 32 | 31 | ||
| 33 | 32 | ||
| @@ -28,6 +28,7 @@ METRIC_VALUE_RANGE_CONFIG = "metric_value_range.conf" | |||
| 28 | MUST_FILTER_LABEL_CONFIG = 'filter_label.conf' | 28 | MUST_FILTER_LABEL_CONFIG = 'filter_label.conf' |
| 29 | DYNAMIC_CONFIG = 'dynamic_config.db' | 29 | DYNAMIC_CONFIG = 'dynamic_config.db' |
| 30 | DATE_FORMAT = '%Y-%m-%d %H:%M:%S' | 30 | DATE_FORMAT = '%Y-%m-%d %H:%M:%S' |
| 31 | +CIPHER_S1 = 'encryption_part_a.bin' | ||
| 31 | 32 | ||
| 32 | with open(os.path.join(MISC_PATH, VERFILE_NAME)) as fp: | 33 | with open(os.path.join(MISC_PATH, VERFILE_NAME)) as fp: |
| 33 | __version__ = fp.readline().strip() | 34 | __version__ = fp.readline().strip() |
| @@ -13,6 +13,9 @@ | |||
| 13 | from dbmind.metadatabase import DynamicConfigDbBase | 13 | from dbmind.metadatabase import DynamicConfigDbBase |
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | +# IV table name | ||
| 17 | +IV_TABLE = 'iv_table' | ||
| 18 | + | ||
| 16 | class DynamicParams(DynamicConfigDbBase): | 19 | class DynamicParams(DynamicConfigDbBase): |
| 17 | __tablename__ = "dynamic_params" | 20 | __tablename__ = "dynamic_params" |
| 18 | 21 | ||
| @@ -16,6 +16,7 @@ port = # Port to connect to meta-data database. | |||
| 16 | username = # User name to connect to meta-data database. | 16 | username = # User name to connect to meta-data database. |
| 17 | password = (null) # Password to connect to meta-data database. | 17 | password = (null) # Password to connect to meta-data database. |
| 18 | database = # Database name to connect to meta-data database. | 18 | database = # Database name to connect to meta-data database. |
| 19 | +ssl_mode = prefer # The ssl mode for ssl connections. Options: disable, prefer, verify-ca. | ||
| 19 | 20 | ||
| 20 | [WORKER] | 21 | [WORKER] |
| 21 | process_num = 0 # Number of worker processes on a local node. Less than or equal to zero means adaptive. | 22 | process_num = 0 # Number of worker processes on a local node. Less than or equal to zero means adaptive. |