From 20f3533163cfab08306c29d249a892f8feead480 Mon Sep 17 00:00:00 2001 From: badrogger Date: Thu, 3 Oct 2024 17:39:47 +0000 Subject: [PATCH 1/6] Add can-update call --- core/updates.py | 13 ++++++++ tests/routes/node_test.py | 69 ++++++++++++++++++++++++++++++--------- web/routes/node.py | 9 +++++ web/routes/schains.py | 1 - 4 files changed, 75 insertions(+), 17 deletions(-) diff --git a/core/updates.py b/core/updates.py index dba476e7b..6251e0244 100644 --- a/core/updates.py +++ b/core/updates.py @@ -23,6 +23,8 @@ from core.node_config import NodeConfig from core.ima.schain import update_predeployed_ima +from core.schains.cleaner import get_schains_on_node +from tools.docker_utils import DockerUtils logger = logging.getLogger(__name__) @@ -56,3 +58,14 @@ def update_node_config_file(skale: Skale, node_config: NodeConfig) -> None: node_config.ip = ip if node_config.name != name: node_config.name = name + + +def is_update_possible(skale: Skale, node_config: NodeConfig, dutils: DockerUtils) -> bool: + schains_on_node = get_schains_on_node(dutils=dutils) + result = True + + for schain_name in schains_on_node: + if skale.node_rotation.is_rotation_active(schain_name): + logger.info('Rotation for %s is in progress', schain_name) + result = False + return result diff --git a/tests/routes/node_test.py b/tests/routes/node_test.py index 61e351d6b..c56e8291b 100644 --- a/tests/routes/node_test.py +++ b/tests/routes/node_test.py @@ -40,22 +40,24 @@ def handler(sender, **kwargs): yield app.test_client() -@pytest.fixture -def node_contracts(skale): - ip, public_ip, port, name = generate_random_node_data() - skale.manager.create_node(ip, port, name, - domain_name=DEFAULT_DOMAIN_NAME, wait_for=True) - node_id = skale.nodes.node_name_to_index(name) - yield node_id - skale.nodes.init_exit(node_id) - skale.manager.node_exit(node_id, wait_for=True) - - -@pytest.fixture -def node_config(node_contracts): - config = NodeConfig() - config.id = node_contracts - return config +# @pytest.fixture +# def node_contracts(skale): +# ip, public_ip, port, name = generate_random_node_data() +# skale.manager.create_node(ip, port, name, +# domain_name=DEFAULT_DOMAIN_NAME, wait_for=True) +# node_id = skale.nodes.node_name_to_index(name) +# try: +# yield node_id +# finally: +# skale.nodes.init_exit(node_id) +# skale.manager.node_exit(node_id, wait_for=True) + + +# @pytest.fixture +# def node_config(node_contracts): +# config = NodeConfig() +# config.id = node_contracts +# return config def test_node_info(skale_bp, skale, node_config): @@ -272,3 +274,38 @@ def test_exit_maintenance(skale_bp, node_config_in_maintenance): ) assert data['status'] == 'error' data['payload'] == {} + + +@pytest.fixture +def skale_bp_node(skale, node_config, schain_on_contracts, schain_db, dutils): + app = Flask(__name__) + app.register_blueprint(node_bp) + + def handler(sender, **kwargs): + g.docker_utils = dutils + g.wallet = skale.wallet + g.config = node_config + + with appcontext_pushed.connected_to(handler, app): + yield app.test_client() + + +def test_can_update(skale, node_config, skale_bp_node): + data = get_bp_data( + skale_bp_node, + get_api_url(BLUEPRINT_NAME, 'can-update'), + ) + assert data['status'] == 'ok' + data['payload'] == {'can-update': True} + + print(skale.schains.get_schains_for_node(node_config.id)) + skale.nodes.init_exit(node_config.id) + skale.manager.node_exit(node_config.id) + + data = get_bp_data( + skale_bp_node, + get_api_url(BLUEPRINT_NAME, 'can-update'), + ) + print(data) + data['payload'] == {'can-update': False} + assert data['status'] == 'ok' diff --git a/web/routes/node.py b/web/routes/node.py index 373603383..9748be28a 100644 --- a/web/routes/node.py +++ b/web/routes/node.py @@ -29,6 +29,7 @@ from core.node import get_meta_info, get_node_hardware_info, get_btrfs_info, get_abi_hash from core.node import check_validator_nodes +from core.updates import is_update_possible from tools.configs.web3 import ABI_FILEPATH, ENDPOINT, UNTRUSTED_PROVIDERS @@ -266,3 +267,11 @@ def ima_abi(): logger.debug(request) abi_hash = get_abi_hash(MAINNET_IMA_ABI_FILEPATH) return construct_ok_response(data=abi_hash) + + +@node_bp.route(get_api_url(BLUEPRINT_NAME, 'can-update'), methods=['GET']) +@g_skale +def update_possible(): + logger.debug(request) + possible = is_update_possible(g.skale, g.config, g.docker_utils) + return construct_ok_response(data={'can_update': possible}) diff --git a/web/routes/schains.py b/web/routes/schains.py index 060a83ffd..58963321e 100644 --- a/web/routes/schains.py +++ b/web/routes/schains.py @@ -85,7 +85,6 @@ def schain_config(): @schains_bp.route(get_api_url(BLUEPRINT_NAME, 'list'), methods=['GET']) @g_skale def schains_list(): - logger.debug(request) logger.debug(request) node_id = g.config.id if node_id is None: From 1bbda9191fc9f8a191f2b545bbe7fe6da3413989 Mon Sep 17 00:00:00 2001 From: badrogger Date: Mon, 7 Oct 2024 12:20:48 +0000 Subject: [PATCH 2/6] Fix tests --- core/updates.py | 18 +++++++++++------- tests/routes/node_test.py | 40 ++++++++++++++++++++++++--------------- web/routes/node.py | 12 ++++++------ 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/core/updates.py b/core/updates.py index 6251e0244..5f360e62a 100644 --- a/core/updates.py +++ b/core/updates.py @@ -23,10 +23,10 @@ from core.node_config import NodeConfig from core.ima.schain import update_predeployed_ima +from core.schains.config.file_manager import ConfigFileManager from core.schains.cleaner import get_schains_on_node from tools.docker_utils import DockerUtils - logger = logging.getLogger(__name__) @@ -60,12 +60,16 @@ def update_node_config_file(skale: Skale, node_config: NodeConfig) -> None: node_config.name = name -def is_update_possible(skale: Skale, node_config: NodeConfig, dutils: DockerUtils) -> bool: +def update_unsafe_for_schains(skale: Skale, node_config: NodeConfig, dutils: DockerUtils) -> list[str]: schains_on_node = get_schains_on_node(dutils=dutils) - result = True - + unsafe_chains = [] for schain_name in schains_on_node: + cfm = ConfigFileManager(schain_name=schain_name) if skale.node_rotation.is_rotation_active(schain_name): - logger.info('Rotation for %s is in progress', schain_name) - result = False - return result + logger.info('Rotation is in progress for %s', schain_name) + unsafe_chains.append(schain_name) + # To handle the gap between SM finish ts and skaled exit time + elif cfm.skaled_config_exists() and not cfm.skaled_config_synced_with_upstream(): + logger.info('Skaled config is not synced with upstream for %s', schain_name) + unsafe_chains.append(schain_name) + return unsafe_chains diff --git a/tests/routes/node_test.py b/tests/routes/node_test.py index c56e8291b..fa7cc0e90 100644 --- a/tests/routes/node_test.py +++ b/tests/routes/node_test.py @@ -14,11 +14,13 @@ from core.node import Node, NodeStatus from core.node_config import NodeConfig -from tests.utils import get_bp_data, post_bp_data +from core.schains.config.file_manager import ConfigFileManager from tools.configs.tg import TG_API_KEY, TG_CHAT_ID from web.routes.node import node_bp from web.helper import get_api_url +from tests.utils import get_bp_data, post_bp_data + CURRENT_TIMESTAMP = 1594903080 CURRENT_DATETIME = datetime.datetime.utcfromtimestamp(CURRENT_TIMESTAMP) @@ -277,35 +279,43 @@ def test_exit_maintenance(skale_bp, node_config_in_maintenance): @pytest.fixture -def skale_bp_node(skale, node_config, schain_on_contracts, schain_db, dutils): +def skale_node_bp(skale, node_config, dutils): app = Flask(__name__) app.register_blueprint(node_bp) def handler(sender, **kwargs): g.docker_utils = dutils g.wallet = skale.wallet - g.config = node_config + g.config = NodeConfig() with appcontext_pushed.connected_to(handler, app): yield app.test_client() -def test_can_update(skale, node_config, skale_bp_node): +def test_update_safe(skale, schain_on_contracts, schain_config, upstreams, skale_node_bp): data = get_bp_data( - skale_bp_node, - get_api_url(BLUEPRINT_NAME, 'can-update'), + skale_node_bp, + get_api_url(BLUEPRINT_NAME, 'update-safe'), ) assert data['status'] == 'ok' - data['payload'] == {'can-update': True} + assert data['payload'] == {'update_safe': True, 'unsafe_chains': []} + + with mock.patch('web.helper.init_skale', return_value=skale): + skale.node_rotation.is_rotation_active = mock.Mock(return_value=True) + data = get_bp_data( + skale_node_bp, + get_api_url(BLUEPRINT_NAME, 'update-safe'), + ) + + assert data['payload'] == {'update_safe': False, 'unsafe_chains': [schain_on_contracts]} + + cfm = ConfigFileManager(schain_on_contracts) - print(skale.schains.get_schains_for_node(node_config.id)) - skale.nodes.init_exit(node_config.id) - skale.manager.node_exit(node_config.id) + cfm.save_skaled_config({}) data = get_bp_data( - skale_bp_node, - get_api_url(BLUEPRINT_NAME, 'can-update'), + skale_node_bp, + get_api_url(BLUEPRINT_NAME, 'update-safe'), ) - print(data) - data['payload'] == {'can-update': False} - assert data['status'] == 'ok' + + assert data['payload'] == {'update_safe': False, 'unsafe_chains': [schain_on_contracts]} diff --git a/web/routes/node.py b/web/routes/node.py index 9748be28a..0d2a5e88a 100644 --- a/web/routes/node.py +++ b/web/routes/node.py @@ -29,8 +29,7 @@ from core.node import get_meta_info, get_node_hardware_info, get_btrfs_info, get_abi_hash from core.node import check_validator_nodes -from core.updates import is_update_possible - +from core.updates import update_unsafe_for_schains from tools.configs.web3 import ABI_FILEPATH, ENDPOINT, UNTRUSTED_PROVIDERS from tools.configs.ima import MAINNET_IMA_ABI_FILEPATH @@ -269,9 +268,10 @@ def ima_abi(): return construct_ok_response(data=abi_hash) -@node_bp.route(get_api_url(BLUEPRINT_NAME, 'can-update'), methods=['GET']) +@node_bp.route(get_api_url(BLUEPRINT_NAME, 'update-safe'), methods=['GET']) @g_skale -def update_possible(): +def update_safe(): logger.debug(request) - possible = is_update_possible(g.skale, g.config, g.docker_utils) - return construct_ok_response(data={'can_update': possible}) + unsafe_chains = update_unsafe_for_schains(g.skale, g.config, g.docker_utils) + safe = len(unsafe_chains) == 0 + return construct_ok_response(data={'update_safe': safe, 'unsafe_chains': unsafe_chains}) From b510641ecbb704143618d1888e0adb8a9864da07 Mon Sep 17 00:00:00 2001 From: badrogger Date: Mon, 7 Oct 2024 17:59:08 +0000 Subject: [PATCH 3/6] Fix linter --- core/updates.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/updates.py b/core/updates.py index 5f360e62a..9a93e4eb9 100644 --- a/core/updates.py +++ b/core/updates.py @@ -60,7 +60,11 @@ def update_node_config_file(skale: Skale, node_config: NodeConfig) -> None: node_config.name = name -def update_unsafe_for_schains(skale: Skale, node_config: NodeConfig, dutils: DockerUtils) -> list[str]: +def update_unsafe_for_schains( + skale: Skale, + node_config: NodeConfig, + dutils: DockerUtils +) -> list[str]: schains_on_node = get_schains_on_node(dutils=dutils) unsafe_chains = [] for schain_name in schains_on_node: From 028fd27035d44eda35379a57a65e4feeae21d024 Mon Sep 17 00:00:00 2001 From: badrogger Date: Mon, 7 Oct 2024 18:28:39 +0000 Subject: [PATCH 4/6] Improve node routes tests --- tests/routes/node_test.py | 48 ++++++--------------------------------- 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/tests/routes/node_test.py b/tests/routes/node_test.py index fa7cc0e90..80f66ab52 100644 --- a/tests/routes/node_test.py +++ b/tests/routes/node_test.py @@ -29,7 +29,7 @@ @pytest.fixture -def skale_bp(skale, dutils): +def skale_bp(skale, node_config, dutils): app = Flask(__name__) app.register_blueprint(node_bp) @@ -42,34 +42,14 @@ def handler(sender, **kwargs): yield app.test_client() -# @pytest.fixture -# def node_contracts(skale): -# ip, public_ip, port, name = generate_random_node_data() -# skale.manager.create_node(ip, port, name, -# domain_name=DEFAULT_DOMAIN_NAME, wait_for=True) -# node_id = skale.nodes.node_name_to_index(name) -# try: -# yield node_id -# finally: -# skale.nodes.init_exit(node_id) -# skale.manager.node_exit(node_id, wait_for=True) - - -# @pytest.fixture -# def node_config(node_contracts): -# config = NodeConfig() -# config.id = node_contracts -# return config - - -def test_node_info(skale_bp, skale, node_config): +def test_node_info(skale_bp, skale, node_config, node_wallets): data = get_bp_data(skale_bp, get_api_url(BLUEPRINT_NAME, 'info')) status = NodeStatus.ACTIVE.value assert data['status'] == 'ok' node_info = data['payload']['node_info'] assert node_info['id'] == node_config.id assert node_info['status'] == status - assert to_checksum_address(node_info['owner']) == skale.wallet.address + assert to_checksum_address(node_info['owner']) == node_wallets[0].address def register_mock(self, ip, public_ip, port, name, domain_name, gas_limit=None, @@ -278,23 +258,9 @@ def test_exit_maintenance(skale_bp, node_config_in_maintenance): data['payload'] == {} -@pytest.fixture -def skale_node_bp(skale, node_config, dutils): - app = Flask(__name__) - app.register_blueprint(node_bp) - - def handler(sender, **kwargs): - g.docker_utils = dutils - g.wallet = skale.wallet - g.config = NodeConfig() - - with appcontext_pushed.connected_to(handler, app): - yield app.test_client() - - -def test_update_safe(skale, schain_on_contracts, schain_config, upstreams, skale_node_bp): +def test_update_safe(skale, schain_on_contracts, schain_config, upstreams, skale_bp): data = get_bp_data( - skale_node_bp, + skale_bp, get_api_url(BLUEPRINT_NAME, 'update-safe'), ) assert data['status'] == 'ok' @@ -303,7 +269,7 @@ def test_update_safe(skale, schain_on_contracts, schain_config, upstreams, skale with mock.patch('web.helper.init_skale', return_value=skale): skale.node_rotation.is_rotation_active = mock.Mock(return_value=True) data = get_bp_data( - skale_node_bp, + skale_bp, get_api_url(BLUEPRINT_NAME, 'update-safe'), ) @@ -314,7 +280,7 @@ def test_update_safe(skale, schain_on_contracts, schain_config, upstreams, skale cfm.save_skaled_config({}) data = get_bp_data( - skale_node_bp, + skale_bp, get_api_url(BLUEPRINT_NAME, 'update-safe'), ) From bea1a351652a4663f2dd28e131d8e93c346a3bd8 Mon Sep 17 00:00:00 2001 From: badrogger Date: Tue, 8 Oct 2024 16:58:01 +0000 Subject: [PATCH 5/6] Fix test_run_monitor_for_schain_left test --- tests/schains/monitor/main_test.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/schains/monitor/main_test.py b/tests/schains/monitor/main_test.py index 865fe081d..f637b4c96 100644 --- a/tests/schains/monitor/main_test.py +++ b/tests/schains/monitor/main_test.py @@ -83,13 +83,14 @@ def test_run_monitor_for_schain_left( ): schain_not_exists = 'not-on-node' upsert_schain_record(schain_not_exists) - with mock.patch('core.schains.monitor.main.keep_tasks_running') as keep_tasks_running_mock: - run_monitor_for_schain( - skale, - skale_ima, - node_config, - get_schain_struct(schain_name=schain_db), - dutils=dutils, - once=True - ) - keep_tasks_running_mock.assert_not_called() + with mock.patch('core.schains.monitor.main.is_node_part_of_chain', return_value=False): + with mock.patch('core.schains.monitor.main.keep_tasks_running') as keep_tasks_running_mock: + run_monitor_for_schain( + skale, + skale_ima, + node_config, + get_schain_struct(schain_name=schain_not_exists), + dutils=dutils, + once=True + ) + keep_tasks_running_mock.assert_not_called() From 38a15cdca0f17566d1f8664ca2613ee3a99e3293 Mon Sep 17 00:00:00 2001 From: badrogger Date: Tue, 8 Oct 2024 18:32:00 +0000 Subject: [PATCH 6/6] Fix tests --- tests/routes/node_test.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/routes/node_test.py b/tests/routes/node_test.py index 80f66ab52..c0bc291a0 100644 --- a/tests/routes/node_test.py +++ b/tests/routes/node_test.py @@ -267,13 +267,13 @@ def test_update_safe(skale, schain_on_contracts, schain_config, upstreams, skale assert data['payload'] == {'update_safe': True, 'unsafe_chains': []} with mock.patch('web.helper.init_skale', return_value=skale): - skale.node_rotation.is_rotation_active = mock.Mock(return_value=True) - data = get_bp_data( - skale_bp, - get_api_url(BLUEPRINT_NAME, 'update-safe'), - ) - - assert data['payload'] == {'update_safe': False, 'unsafe_chains': [schain_on_contracts]} + with mock.patch.object(skale.node_rotation, 'is_rotation_active', return_value=False): + skale.node_rotation.is_rotation_active = mock.Mock(return_value=True) + data = get_bp_data( + skale_bp, + get_api_url(BLUEPRINT_NAME, 'update-safe'), + ) + assert data['payload'] == {'update_safe': False, 'unsafe_chains': [schain_on_contracts]} cfm = ConfigFileManager(schain_on_contracts)