You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-07-30 19:23:07 +03:00
feat(cmapi): MCOL-5133: Stage1 to stand alone cli tool. (#3378)
[add] cluster api client class [fix] cli cluster_app using cluster api client [add] ClusterAction Enum [add] toggle_cluster_state function to reduce code duplication
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
"""Module contains Cluster business logic functions."""
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
|
||||
import requests
|
||||
@ -22,26 +23,61 @@ from mcs_node_control.models.misc import get_dbrm_master
|
||||
from mcs_node_control.models.node_config import NodeConfig
|
||||
|
||||
|
||||
class ClusterAction(Enum):
|
||||
START = 'start'
|
||||
STOP = 'stop'
|
||||
|
||||
|
||||
def toggle_cluster_state(action: ClusterAction, config: str) -> dict:
|
||||
"""
|
||||
Toggle the state of the cluster (start or stop).
|
||||
|
||||
:param action: The cluster action to perform.
|
||||
(ClusterAction.START or ClusterAction.STOP).
|
||||
:type action: ClusterAction
|
||||
:param config: The path to the MariaDB Columnstore configuration file.
|
||||
:type config: str
|
||||
"""
|
||||
if action == ClusterAction.START:
|
||||
maintainance_flag = True
|
||||
elif action == ClusterAction.STOP:
|
||||
maintainance_flag = True
|
||||
else:
|
||||
raise ValueError(
|
||||
'Invalid action. Use ClusterAction.START or ClusterAction.STOP.'
|
||||
)
|
||||
|
||||
switch_node_maintenance(maintainance_flag)
|
||||
update_revision_and_manager()
|
||||
|
||||
# TODO: move this from multiple places to one
|
||||
try:
|
||||
broadcast_successful = broadcast_new_config(config)
|
||||
except Exception as err:
|
||||
raise CMAPIBasicError(
|
||||
'Error while distributing config file.'
|
||||
) from err
|
||||
|
||||
if not broadcast_successful:
|
||||
raise CMAPIBasicError('Config distribution isn\'t successful.')
|
||||
|
||||
|
||||
class ClusterHandler():
|
||||
"""Class for handling MCS Cluster operations."""
|
||||
|
||||
@staticmethod
|
||||
def status(
|
||||
config: str = DEFAULT_MCS_CONF_PATH,
|
||||
logger: logging.Logger = logging.getLogger('cmapi_server')
|
||||
) -> dict:
|
||||
def status(config: str = DEFAULT_MCS_CONF_PATH) -> dict:
|
||||
"""Method to get MCS Cluster status information
|
||||
|
||||
:param config: columnstore xml config file path,
|
||||
defaults to DEFAULT_MCS_CONF_PATH
|
||||
:type config: str, optional
|
||||
:param logger: logger, defaults to logging.getLogger('cmapi_server')
|
||||
:type logger: logging.Logger, optional
|
||||
:raises CMAPIBasicError: if catch some exception while getting status
|
||||
from each node separately
|
||||
:return: status result
|
||||
:rtype: dict
|
||||
"""
|
||||
logger: logging.Logger = logging.getLogger('cmapi_server')
|
||||
logger.debug('Cluster status command called. Getting status.')
|
||||
|
||||
response = {'timestamp': str(datetime.now())}
|
||||
@ -73,78 +109,36 @@ class ClusterHandler():
|
||||
|
||||
@staticmethod
|
||||
def start(
|
||||
config: str = DEFAULT_MCS_CONF_PATH,
|
||||
logger: logging.Logger = logging.getLogger('cmapi_server')
|
||||
config: str = DEFAULT_MCS_CONF_PATH, in_transaction: bool = False
|
||||
) -> dict:
|
||||
"""Method to start MCS Cluster.
|
||||
|
||||
:param config: columnstore xml config file path,
|
||||
defaults to DEFAULT_MCS_CONF_PATH
|
||||
:type config: str, optional
|
||||
:param logger: logger, defaults to logging.getLogger('cmapi_server')
|
||||
:type logger: logging.Logger, optional
|
||||
:raises CMAPIBasicError: on exception while starting transaction
|
||||
:raises CMAPIBasicError: if transaction start isn't successful
|
||||
:param in_transaction: is function called in existing transaction or no
|
||||
If we started transaction in cli tool than we
|
||||
don't need to handle it here again
|
||||
:type in_transaction: bool
|
||||
:raises CMAPIBasicError: if no nodes in the cluster
|
||||
:raises CMAPIBasicError: on exception while distributing new config
|
||||
:raises CMAPIBasicError: on unsuccessful distibuting config file
|
||||
:raises CMAPIBasicError: on exception while committing transaction
|
||||
:return: start timestamp
|
||||
:rtype: dict
|
||||
"""
|
||||
logger.debug('Cluster start command called. Starting the cluster.')
|
||||
start_time = str(datetime.now())
|
||||
transaction_id = get_id()
|
||||
logger: logging.Logger = logging.getLogger('cmapi_server')
|
||||
logger.info('Cluster start command called. Starting the cluster.')
|
||||
operation_start_time = str(datetime.now())
|
||||
if not in_transaction:
|
||||
with TransactionManager():
|
||||
toggle_cluster_state(ClusterAction.START, config)
|
||||
else:
|
||||
toggle_cluster_state(ClusterAction.START, config)
|
||||
|
||||
try:
|
||||
suceeded, transaction_id, successes = start_transaction(
|
||||
cs_config_filename=config, txn_id=transaction_id
|
||||
)
|
||||
except Exception as err:
|
||||
rollback_transaction(transaction_id, cs_config_filename=config)
|
||||
raise CMAPIBasicError(
|
||||
'Error while starting the transaction.'
|
||||
) from err
|
||||
if not suceeded:
|
||||
rollback_transaction(transaction_id, cs_config_filename=config)
|
||||
raise CMAPIBasicError('Starting transaction isn\'t successful.')
|
||||
|
||||
if suceeded and len(successes) == 0:
|
||||
rollback_transaction(transaction_id, cs_config_filename=config)
|
||||
raise CMAPIBasicError('There are no nodes in the cluster.')
|
||||
|
||||
switch_node_maintenance(False)
|
||||
update_revision_and_manager()
|
||||
|
||||
# TODO: move this from multiple places to one, eg to helpers
|
||||
try:
|
||||
broadcast_successful = broadcast_new_config(config)
|
||||
except Exception as err:
|
||||
rollback_transaction(transaction_id, cs_config_filename=config)
|
||||
raise CMAPIBasicError(
|
||||
'Error while distributing config file.'
|
||||
) from err
|
||||
|
||||
if not broadcast_successful:
|
||||
rollback_transaction(transaction_id, cs_config_filename=config)
|
||||
raise CMAPIBasicError('Config distribution isn\'t successful.')
|
||||
|
||||
try:
|
||||
commit_transaction(transaction_id, cs_config_filename=config)
|
||||
except Exception as err:
|
||||
rollback_transaction(transaction_id, cs_config_filename=config)
|
||||
raise CMAPIBasicError(
|
||||
'Error while committing transaction.'
|
||||
) from err
|
||||
|
||||
logger.debug('Successfully finished cluster start.')
|
||||
return {'timestamp': start_time}
|
||||
logger.info('Successfully finished cluster start.')
|
||||
return {'timestamp': operation_start_time}
|
||||
|
||||
@staticmethod
|
||||
def shutdown(
|
||||
config: str = DEFAULT_MCS_CONF_PATH,
|
||||
logger: logging.Logger = logging.getLogger('cmapi_server'),
|
||||
in_transaction: bool = False,
|
||||
config: str = DEFAULT_MCS_CONF_PATH, in_transaction: bool = False,
|
||||
timeout: int = 15
|
||||
) -> dict:
|
||||
"""Method to stop the MCS Cluster.
|
||||
@ -152,8 +146,6 @@ class ClusterHandler():
|
||||
:param config: columnstore xml config file path,
|
||||
defaults to DEFAULT_MCS_CONF_PATH
|
||||
:type config: str, optional
|
||||
:param logger: logger, defaults to logging.getLogger('cmapi_server')
|
||||
:type logger: logging.Logger, optional
|
||||
:param in_transaction: is function called in existing transaction or no
|
||||
:type in_transaction: bool
|
||||
:param timeout: timeout in seconds to gracefully stop DMLProc
|
||||
@ -163,35 +155,19 @@ class ClusterHandler():
|
||||
:return: start timestamp
|
||||
:rtype: dict
|
||||
"""
|
||||
logger: logging.Logger = logging.getLogger('cmapi_server')
|
||||
logger.debug(
|
||||
'Cluster shutdown command called. Shutting down the cluster.'
|
||||
)
|
||||
|
||||
def process_shutdown():
|
||||
"""Raw node shutdown processing."""
|
||||
switch_node_maintenance(True)
|
||||
update_revision_and_manager()
|
||||
|
||||
# TODO: move this from multiple places to one, eg to helpers
|
||||
try:
|
||||
broadcast_successful = broadcast_new_config(config)
|
||||
except Exception as err:
|
||||
raise CMAPIBasicError(
|
||||
'Error while distributing config file.'
|
||||
) from err
|
||||
|
||||
if not broadcast_successful:
|
||||
raise CMAPIBasicError('Config distribution isn\'t successful.')
|
||||
|
||||
start_time = str(datetime.now())
|
||||
operation_start_time = str(datetime.now())
|
||||
if not in_transaction:
|
||||
with TransactionManager():
|
||||
process_shutdown()
|
||||
toggle_cluster_state(ClusterAction.STOP, config)
|
||||
else:
|
||||
process_shutdown()
|
||||
toggle_cluster_state(ClusterAction.STOP, config)
|
||||
|
||||
logger.debug('Successfully finished shutting down the cluster.')
|
||||
return {'timestamp': start_time}
|
||||
return {'timestamp': operation_start_time}
|
||||
|
||||
@staticmethod
|
||||
def add_node(
|
||||
|
Reference in New Issue
Block a user