1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-07-30 19:23:07 +03:00

MCOL-5806: added ability to start node in read-only mode

* feat(cmapi): add read_only param for API add node endpoint
* style(cmapi): fixes for string length and quotes

Add dbroots of other nodes to the read-only node

On every node change adjust dbroots in the read-only nodes

Fix logging (trace level) in tests
This commit is contained in:
Alexander Presnyakov
2025-03-12 13:21:37 +00:00
committed by Serguey Zefirov
parent a27f1a1f98
commit c59e2aa9ee
18 changed files with 508 additions and 101 deletions

View File

@ -1,26 +1,27 @@
import configparser
from contextlib import contextmanager
import grp
import logging
import pwd
import re
import socket
from os import mkdir, replace, chown
from os import chown, mkdir, replace
from pathlib import Path
from shutil import copyfile
from xml.dom import minidom # to pick up pretty printing functionality
from typing import Optional
from xml.dom import minidom # to pick up pretty printing functionality
from lxml import etree
from cmapi_server.constants import (
DEFAULT_MCS_CONF_PATH, DEFAULT_SM_CONF_PATH,
DEFAULT_MCS_CONF_PATH,
DEFAULT_SM_CONF_PATH,
MCS_MODULE_FILE_PATH,
)
# from cmapi_server.managers.process import MCSProcessManager
from mcs_node_control.models.misc import (
read_module_id, get_dbroots_list
)
from mcs_node_control.models.network_ifaces import get_network_interfaces
# from cmapi_server.managers.process import MCSProcessManager
from mcs_node_control.models.misc import get_dbroots_list, read_module_id
from mcs_node_control.models.network_ifaces import get_network_interfaces
module_logger = logging.getLogger()
@ -36,7 +37,7 @@ class NodeConfig:
"""
def get_current_config_root(
self, config_filename: str = DEFAULT_MCS_CONF_PATH, upgrade=True
):
) -> etree.Element:
"""Retrieves current configuration.
Read the config and returns Element.
@ -49,7 +50,7 @@ class NodeConfig:
self.upgrade_config(tree=tree, upgrade=upgrade)
return tree.getroot()
def get_root_from_string(self, config_string: str):
def get_root_from_string(self, config_string: str) -> etree.Element:
root = etree.fromstring(config_string)
self.upgrade_config(root=root)
return root
@ -137,6 +138,26 @@ class NodeConfig:
f.write(self.to_string(tree))
replace(tmp_filename, filename) # atomic replacement
@contextmanager
def modify_config(
self,
input_config_filename: str = DEFAULT_MCS_CONF_PATH,
output_config_filename: Optional[str] = None,
):
"""Context manager to modify the config file
If exception is raised, the config file is not modified and exception is re-raised
If output_config_filename is not provided, the input config file is modified
"""
try:
c_root = self.get_current_config_root(input_config_filename)
yield c_root
except Exception as e:
logging.error(f"modify_config(): Caught exception: '{str(e)}', config file not modified")
raise
else:
output_config_filename = output_config_filename or input_config_filename
self.write_config(c_root, output_config_filename)
def to_string(self, tree):
# TODO: try to use lxml to do this to avoid the add'l dependency
xmlstr = minidom.parseString(etree.tostring(tree)).toprettyxml(
@ -566,4 +587,18 @@ has dbroot {subel.text}')
for i in range(1, mod_count+1):
for j in range(1, int(smc_node.find(f"./ModuleDBRootCount{i}-3").text) + 1):
dbroots.append(smc_node.find(f"./ModuleDBRootID{i}-{j}-3").text)
return dbroots
def get_read_only_nodes(self, root=None) -> list[str]:
"""Get names of read only nodes from config"""
root = root or self.get_current_config_root()
return [node.text for node in root.findall('./ReadOnlyNodes/Node')]
def is_read_only(self, root=None) -> bool:
"""Checks if this node is in read-only mode"""
root = root or self.get_current_config_root()
read_only_nodes = set(self.get_read_only_nodes(root))
my_names = set(self.get_network_addresses_and_names())
return bool(read_only_nodes.intersection(my_names))