From 6908f68cc7026b53910a9e458fde016468ab31eb Mon Sep 17 00:00:00 2001 From: badrogger Date: Thu, 13 Jun 2024 15:43:49 +0000 Subject: [PATCH] Toggle repair through node_cli schain status file --- node_cli/core/schains.py | 31 +++++---- node_cli/utils/helper.py | 17 ++++- tests/conftest.py | 24 +++++-- tests/{ => core}/core_checks_test.py | 0 tests/{ => core}/core_node_test.py | 0 tests/core/core_schains_test.py | 34 ++++++++++ tests/core_ssl_test.py | 95 ---------------------------- 7 files changed, 83 insertions(+), 118 deletions(-) rename tests/{ => core}/core_checks_test.py (100%) rename tests/{ => core}/core_node_test.py (100%) create mode 100644 tests/core/core_schains_test.py delete mode 100644 tests/core_ssl_test.py diff --git a/node_cli/core/schains.py b/node_cli/core/schains.py index f9fa64aa..652210d1 100644 --- a/node_cli/core/schains.py +++ b/node_cli/core/schains.py @@ -2,6 +2,7 @@ import os import pprint import shutil +import time from pathlib import Path from typing import Dict, Optional @@ -16,8 +17,7 @@ from node_cli.utils.helper import ( get_request, error_exit, - safe_load_yml, - post_request + safe_load_yml ) from node_cli.utils.exit_codes import CLIExitCodes from node_cli.utils.print_formatters import ( @@ -27,7 +27,7 @@ print_schains ) from node_cli.utils.docker_utils import ensure_volume, is_volume_exists -from node_cli.utils.helper import read_json, run_cmd +from node_cli.utils.helper import read_json, run_cmd, save_json from lvmpy.src.core import mount, volume_mountpoint @@ -89,22 +89,25 @@ def show_config(name: str) -> None: error_exit(payload, exit_code=CLIExitCodes.BAD_API_RESPONSE) +def get_node_cli_schain_status_filepath(schain_name: str) -> str: + return os.path.join(SCHAIN_NODE_DATA_PATH, schain_name, 'node-cli.status') + + +def update_node_cli_schain_status(schain_name: str, status: dict) -> None: + path = get_node_cli_schain_status_filepath(schain_name) + save_json(path, status) + + def toggle_schain_repair_mode( schain: str, snapshot_from: Optional[str] = None ) -> None: - json_params = {'schain_name': schain} + ts = int(time.time()) + status = {'schain_name': schain, 'repair_ts': ts} if snapshot_from: - json_params.update({'snapshot_from': snapshot_from}) - status, payload = post_request( - blueprint=BLUEPRINT_NAME, - method='repair', - json=json_params - ) - if status == 'ok': - print('Schain has been set for repair') - else: - error_exit(payload, exit_code=CLIExitCodes.BAD_API_RESPONSE) + status.update({'snapshot_from': snapshot_from}) + update_node_cli_schain_status(schain, status) + print('Schain has been set for repair') def describe(schain: str, raw=False) -> None: diff --git a/node_cli/utils/helper.py b/node_cli/utils/helper.py index 4d76164b..cba65ddd 100644 --- a/node_cli/utils/helper.py +++ b/node_cli/utils/helper.py @@ -22,6 +22,7 @@ import os import re import sys +import uuid from urllib.parse import urlparse import yaml @@ -77,16 +78,22 @@ class InvalidEnvFileError(Exception): pass -def read_json(path): +def read_json(path: str) -> dict: with open(path, encoding='utf-8') as data_file: return json.loads(data_file.read()) -def write_json(path, content): +def write_json(path: str, content: dict) -> None: with open(path, 'w') as outfile: json.dump(content, outfile, indent=4) +def save_json(path: str, content: dict) -> None: + tmp_path = get_tmp_path(path) + write_json(tmp_path, content) + shutil.move(tmp_path, path) + + def init_file(path, content=None): if not os.path.exists(path): write_json(path, content) @@ -400,3 +407,9 @@ def convert(self, value, param, ctx): URL_TYPE = UrlType() IP_TYPE = IpType() + + +def get_tmp_path(path: str) -> str: + base, ext = os.path.splitext(path) + salt = uuid.uuid4().hex[:5] + return base + salt + '.tmp' + ext diff --git a/tests/conftest.py b/tests/conftest.py index 9504523f..93d82521 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -29,13 +29,14 @@ import yaml from node_cli.configs import ( - CONTAINER_CONFIG_TMP_PATH, - GLOBAL_SKALE_CONF_FILEPATH, - GLOBAL_SKALE_DIR, - META_FILEPATH, - NGINX_CONTAINER_NAME, - REMOVED_CONTAINERS_FOLDER_PATH, - STATIC_PARAMS_FILEPATH + CONTAINER_CONFIG_TMP_PATH, + GLOBAL_SKALE_CONF_FILEPATH, + GLOBAL_SKALE_DIR, + META_FILEPATH, + NGINX_CONTAINER_NAME, + REMOVED_CONTAINERS_FOLDER_PATH, + STATIC_PARAMS_FILEPATH, + SCHAIN_NODE_DATA_PATH ) from node_cli.configs.node_options import NODE_OPTIONS_FILEPATH from node_cli.configs.ssl import SSL_FOLDER_PATH @@ -302,3 +303,12 @@ def tmp_config_dir(): yield CONTAINER_CONFIG_TMP_PATH finally: shutil.rmtree(CONTAINER_CONFIG_TMP_PATH) + + +@pytest.fixture +def tmp_schains_dir(): + os.makedirs(SCHAIN_NODE_DATA_PATH) + try: + yield SCHAIN_NODE_DATA_PATH + finally: + shutil.rmtree(SCHAIN_NODE_DATA_PATH) diff --git a/tests/core_checks_test.py b/tests/core/core_checks_test.py similarity index 100% rename from tests/core_checks_test.py rename to tests/core/core_checks_test.py diff --git a/tests/core_node_test.py b/tests/core/core_node_test.py similarity index 100% rename from tests/core_node_test.py rename to tests/core/core_node_test.py diff --git a/tests/core/core_schains_test.py b/tests/core/core_schains_test.py new file mode 100644 index 00000000..29ef337a --- /dev/null +++ b/tests/core/core_schains_test.py @@ -0,0 +1,34 @@ +import os +import datetime + +import freezegun + +from node_cli.core.schains import toggle_schain_repair_mode +from node_cli.utils.helper import read_json + + +CURRENT_TIMESTAMP = 1594903080 +CURRENT_DATETIME = datetime.datetime.utcfromtimestamp(CURRENT_TIMESTAMP) + + +@freezegun.freeze_time(CURRENT_DATETIME) +def test_toggle_repair_mode(tmp_schains_dir): + schain_name = "test_schain" + schain_folder = os.path.join(tmp_schains_dir, schain_name) + os.mkdir(schain_folder) + toggle_schain_repair_mode(schain_name) + schain_status_path = os.path.join(schain_folder, "node-cli.status") + assert os.path.isfile(schain_status_path) + + assert read_json(schain_status_path) == { + 'repair_ts': CURRENT_TIMESTAMP, + 'schain_name': 'test_schain', + } + + toggle_schain_repair_mode(schain_name, snapshot_from='127.0.0.1') + + assert read_json(schain_status_path) == { + 'repair_ts': CURRENT_TIMESTAMP, + 'schain_name': 'test_schain', + 'snapshot_from': '127.0.0.1', + } diff --git a/tests/core_ssl_test.py b/tests/core_ssl_test.py deleted file mode 100644 index a7b3eaff..00000000 --- a/tests/core_ssl_test.py +++ /dev/null @@ -1,95 +0,0 @@ -import os -import pathlib -from docker import APIClient - -import pytest - -from node_cli.core.ssl import upload_cert -from node_cli.core.ssl.check import check_cert_openssl, SSLHealthcheckError -from node_cli.utils.helper import run_cmd -from node_cli.configs.ssl import SSL_CERT_FILEPATH, SSL_KEY_FILEPATH -from node_cli.configs import NGINX_CONTAINER_NAME - - -HOST = '127.0.0.1' - - -@pytest.fixture -def cert_key_pair(): - cert_path = os.path.abspath('ssl-test-cert') - key_path = os.path.abspath('ssl-test-key') - run_cmd([ - 'openssl', 'req', - '-newkey', 'rsa:4096', - '-x509', - '-sha256', - '-days', '365', - '-nodes', - '-subj', '/', - '-out', cert_path, - '-keyout', key_path - ]) - yield cert_path, key_path - if os.path.isfile(cert_path): - pathlib.Path(cert_path).unlink() - if os.path.isfile(key_path): - pathlib.Path(key_path).unlink() - - -@pytest.fixture -def bad_cert(cert_key_pair): - cert, key = cert_key_pair - with open(cert, 'w') as cert_file: - cert_file.write('WRONG CERT') - yield cert, key - - -@pytest.fixture -def bad_key(cert_key_pair): - cert, key = cert_key_pair - with open(key, 'w') as key_file: - key_file.write('WRONG KEY') - yield cert, key - - -def test_verify_cert(cert_key_pair): - cert, key = cert_key_pair - check_cert_openssl(cert, key, host=HOST, no_client=True) - - -def test_verify_cert_self_signed_alert(cert_key_pair): - cert, key = cert_key_pair - with pytest.raises(SSLHealthcheckError): - check_cert_openssl(cert, key, host=HOST, no_client=False) - - -def test_verify_cert_bad_cert(bad_cert): - cert, key = bad_cert - with pytest.raises(SSLHealthcheckError): - check_cert_openssl(cert, key, host=HOST, no_client=True) - - -def test_verify_cert_bad_key(bad_key): - cert, key = bad_key - with pytest.raises(SSLHealthcheckError): - check_cert_openssl(cert, key, host=HOST, no_client=True) - - -def test_upload_cert(cert_key_pair, nginx_container, dutils): - cert, key = cert_key_pair - - docker_api = APIClient() - nginx_container = dutils.containers.get(NGINX_CONTAINER_NAME) - stats = docker_api.inspect_container(nginx_container.id) - started_at = stats['State']['StartedAt'] - - assert not os.path.isfile(SSL_KEY_FILEPATH) - assert not os.path.isfile(SSL_CERT_FILEPATH) - - upload_cert(cert, key, force=False, no_client=True) - - assert os.path.isfile(SSL_KEY_FILEPATH) - assert os.path.isfile(SSL_CERT_FILEPATH) - - stats = docker_api.inspect_container(nginx_container.id) - assert started_at != stats['State']['StartedAt']