From 9cc74586f12e3cae9ab2002407a76b5f469a60b2 Mon Sep 17 00:00:00 2001 From: mariadb-AlanMologorsky Date: Fri, 27 Dec 2024 15:55:27 +0300 Subject: [PATCH] MCOL-5133: Stage1 to stand alone cli tool. [add] cluster api client class [fix] cli cluster_app using cluster api client --- cmapi/cmapi_server/controllers/api_clients.py | 110 ++++++++++++++++++ cmapi/mcs_cluster_tool/cluster_app.py | 29 ++--- 2 files changed, 121 insertions(+), 18 deletions(-) create mode 100644 cmapi/cmapi_server/controllers/api_clients.py diff --git a/cmapi/cmapi_server/controllers/api_clients.py b/cmapi/cmapi_server/controllers/api_clients.py new file mode 100644 index 0000000000..a3b2861b6e --- /dev/null +++ b/cmapi/cmapi_server/controllers/api_clients.py @@ -0,0 +1,110 @@ +import requests +from typing import Any, Dict, Optional, Union +from cmapi_server.controllers.dispatcher import _version + + +class ClusterControllerClient: + def __init__(self, base_url: str): + """Initialize the ClusterControllerClient with the base URL. + + :param base_url: The base URL for the API endpoints. + """ + self.base_url = base_url + + def start_cluster(self) -> Union[Dict[str, Any], Dict[str, str]]: + """Start the cluster. + + :return: The response from the API. + """ + return self._request('put', 'start') + + def shutdown_cluster(self) -> Union[Dict[str, Any], Dict[str, str]]: + """Shutdown the cluster. + + :return: The response from the API. + """ + return self._request('put', 'shutdown') + + def set_mode(self, mode: str) -> Union[Dict[str, Any], Dict[str, str]]: + """Set the cluster mode. + + :param mode: The mode to set. + :return: The response from the API. + """ + return self._request('put', 'mode-set', {'mode': mode}) + + def add_node( + self, node_info: Dict[str, Any] + ) -> Union[Dict[str, Any], Dict[str, str]]: + """Add a node to the cluster. + + :param node_info: Information about the node to add. + :return: The response from the API. + """ + return self._request('put', 'node', node_info) + + def remove_node( + self, node_id: str + ) -> Union[Dict[str, Any], Dict[str, str]]: + """Remove a node from the cluster. + + :param node_id: The ID of the node to remove. + :return: The response from the API. + """ + return self._request('delete', 'node', {'node_id': node_id}) + + def get_status(self) -> Union[Dict[str, Any], Dict[str, str]]: + """Get the status of the cluster. + + :return: The response from the API. + """ + return self._request('get', 'status') + + def set_api_key( + self, api_key: str + ) -> Union[Dict[str, Any], Dict[str, str]]: + """Set the API key for the cluster. + + :param api_key: The API key to set. + :return: The response from the API. + """ + return self._request('put', 'apikey-set', {'api_key': api_key}) + + def set_log_level( + self, log_level: str + ) -> Union[Dict[str, Any], Dict[str, str]]: + """Set the log level for the cluster. + + :param log_level: The log level to set. + :return: The response from the API. + """ + return self._request('put', 'log-level', {'log_level': log_level}) + + def load_s3data( + self, s3data_info: Dict[str, Any] + ) -> Union[Dict[str, Any], Dict[str, str]]: + """Load S3 data into the cluster. + + :param s3data_info: Information about the S3 data to load. + :return: The response from the API. + """ + return self._request('put', 'load_s3data', s3data_info) + + def _request( + self, method: str, endpoint: str, + data: Optional[Dict[str, Any]] = None + ) -> Union[Dict[str, Any], Dict[str, str]]: + """Make a request to the API. + + :param method: The HTTP method to use. + :param endpoint: The API endpoint to call. + :param data: The data to send with the request. + :return: The response from the API. + """ + url = f'{self.base_url}/cmapi/{_version}/cluster/{endpoint}' + try: + response = requests.request(method, url, json=data) + response.raise_for_status() + return response.json() + except requests.exceptions.RequestException as e: + return {'error': str(e)} diff --git a/cmapi/mcs_cluster_tool/cluster_app.py b/cmapi/mcs_cluster_tool/cluster_app.py index 07934f31eb..26f1b89b5e 100644 --- a/cmapi/mcs_cluster_tool/cluster_app.py +++ b/cmapi/mcs_cluster_tool/cluster_app.py @@ -23,6 +23,7 @@ from cmapi_server.managers.transaction import TransactionManager from mcs_cluster_tool.decorators import handle_output from mcs_node_control.models.node_config import NodeConfig +from cmapi.cmapi_server.controllers.api_clients import ClusterControllerClient logger = logging.getLogger('mcs_cli') @@ -34,13 +35,13 @@ set_app = typer.Typer(help='Set cluster parameters.') app.add_typer(set_app, name='set') +client = ClusterControllerClient(base_url="http://localhost:8640") @app.command() @handle_output def status(): """Get status information.""" - return ClusterHandler.status(logger=logger) - + return client.get_status() @app.command() @handle_output @@ -165,21 +166,19 @@ def stop( @handle_output def start(): """Start the Columnstore cluster.""" - return ClusterHandler.start(logger=logger) - + return client.start_cluster() @app.command() @handle_output def restart(): """Restart the Columnstore cluster.""" - stop_result = ClusterHandler.shutdown(logger=logger) + stop_result = client.shutdown_cluster() if 'error' in stop_result: return stop_result - result = ClusterHandler.start(logger=logger) + result = client.start_cluster() result['stop_timestamp'] = stop_result['timestamp'] return result - @node_app.command() @handle_output def add( @@ -195,10 +194,9 @@ def add( """Add nodes to the Columnstore cluster.""" result = [] for node in nodes: - result.append(ClusterHandler.add_node(node, logger=logger)) + result.append(client.add_node({'node': node})) return result - @node_app.command() @handle_output def remove(nodes: Optional[List[str]] = typer.Option( @@ -213,10 +211,9 @@ def remove(nodes: Optional[List[str]] = typer.Option( """Remove nodes from the Columnstore cluster.""" result = [] for node in nodes: - result.append(ClusterHandler.remove_node(node, logger=logger)) + result.append(client.remove_node(node)) return result - @set_app.command() @handle_output def mode(cluster_mode: str = typer.Option( @@ -233,8 +230,7 @@ def mode(cluster_mode: str = typer.Option( raise typer.BadParameter( '"readonly" or "readwrite" are the only acceptable modes now.' ) - return ClusterHandler.set_mode(cluster_mode, logger=logger) - + return client.set_mode(cluster_mode) @set_app.command() @handle_output @@ -246,10 +242,7 @@ def api_key(key: str = typer.Option(..., help='API key to set.')): if not key: raise typer.BadParameter('Empty API key not allowed.') - totp = pyotp.TOTP(SECRET_KEY) - - return ClusterHandler.set_api_key(key, totp.now(), logger=logger) - + return client.set_api_key(key) @set_app.command() @handle_output @@ -261,4 +254,4 @@ def log_level(level: str = typer.Option(..., help='Logging level to set.')): if not level: raise typer.BadParameter('Empty log level not allowed.') - return ClusterHandler.set_log_level(level, logger=logger) + return client.set_log_level(level)