Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.5.x beta #791

Merged
merged 34 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6908f68
Toggle repair through node_cli schain status file
badrogger Jun 13, 2024
f6d413a
Rename ncli status file
badrogger Jun 20, 2024
38d41e2
Fix tests
badrogger Jul 18, 2024
5840e3a
Fix linter
badrogger Jul 18, 2024
178d0b8
Merge branch 'v2.5.x' into fix-repair
badrogger Sep 24, 2024
2ddd6df
Bump version
badrogger Sep 24, 2024
f8e1fa0
Merge pull request #772 from skalenetwork/fix-repair
badrogger Sep 24, 2024
e566b89
Run `update_meta` in `turn-on` method
alexgex Sep 26, 2024
198d1e4
Add quotes to publish branch pattern
badrogger Sep 27, 2024
ae52add
Merge pull request #785 from skalenetwork/fix-os-version-check
DmytroNazarenko Sep 27, 2024
ccb850e
Check that is safe to update
badrogger Oct 4, 2024
3a0c3ff
Fix safe update check. Add tests
badrogger Oct 7, 2024
fb32776
Fix tests
badrogger Oct 8, 2024
bc3f446
Fix linter
badrogger Oct 8, 2024
4bf7b94
Fix tests
badrogger Oct 8, 2024
dd82abe
Fix linter
badrogger Oct 8, 2024
d2e33df
Fix typo
badrogger Oct 9, 2024
f3348a1
Fix typo
badrogger Oct 9, 2024
62ca678
Fix typo
badrogger Oct 9, 2024
5a53762
Merge pull request #786 from skalenetwork/safe-update
badrogger Oct 9, 2024
5ca8eeb
Add --snapshot-from option for sync-node init
badrogger Oct 10, 2024
fc308fa
Fix update_sync test
badrogger Oct 11, 2024
f9cefef
Add sync-node repair command
badrogger Oct 14, 2024
f044833
Add cleanup_sync_datadir test
badrogger Oct 14, 2024
3cdc4f6
Merge pull request #787 from skalenetwork/snapshot-from-sync-node
badrogger Oct 15, 2024
9cd26a7
Add repair_sync test
badrogger Oct 15, 2024
c8611e9
Fix linter
badrogger Oct 15, 2024
363b8cd
Fix tests
badrogger Oct 15, 2024
110b498
Fix tests
badrogger Oct 15, 2024
ccbfa96
Merge pull request #788 from skalenetwork/repair-sync-node
badrogger Oct 16, 2024
22d6702
Fix sync init
badrogger Oct 16, 2024
d706021
Switch to URL_TYPE for --snapshot-from
badrogger Oct 16, 2024
fd57233
Merge pull request #789 from skalenetwork/fix-sync-init
badrogger Oct 16, 2024
ee38092
Merge pull request #790 from skalenetwork/v2.5.x
DmytroNazarenko Oct 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
- develop
- beta
- stable
- v*.*.*
- 'v*.*.*'

jobs:
create_release:
Expand Down
2 changes: 1 addition & 1 deletion node_cli/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '2.4.1'
__version__ = '2.5.0'

if __name__ == "__main__":
print(__version__)
22 changes: 18 additions & 4 deletions node_cli/cli/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,17 @@ def init_node(env_file):
expose_value=False,
prompt='Are you sure you want to update SKALE node software?')
@click.option('--pull-config', 'pull_config_for_schain', hidden=True, type=str)
@click.option(
'--unsafe',
'unsafe_ok',
help='Allow unsafe update',
hidden=True,
is_flag=True
)
@click.argument('env_file')
@streamed_cmd
def update_node(env_file, pull_config_for_schain):
update(env_file, pull_config_for_schain)
def update_node(env_file, pull_config_for_schain, unsafe_ok):
update(env_file, pull_config_for_schain, unsafe_ok)


@node.command('signature', help='Get node signature for given validator id')
Expand Down Expand Up @@ -173,9 +180,16 @@ def remove_node_from_maintenance():
@click.option('--yes', is_flag=True, callback=abort_if_false,
expose_value=False,
prompt='Are you sure you want to turn off the node?')
@click.option(
'--unsafe',
'unsafe_ok',
help='Allow unsafe turn-off',
hidden=True,
is_flag=True
)
@streamed_cmd
def _turn_off(maintenance_on):
turn_off(maintenance_on)
def _turn_off(maintenance_on, unsafe_ok):
turn_off(maintenance_on, unsafe_ok)


@node.command('turn-on', help='Turn on the node')
Expand Down
4 changes: 2 additions & 2 deletions node_cli/cli/schains.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import click

from node_cli.utils.helper import abort_if_false, IP_TYPE
from node_cli.utils.helper import abort_if_false, URL_TYPE
from node_cli.core.schains import (
describe,
get_schain_firewall_rules,
Expand Down Expand Up @@ -87,7 +87,7 @@ def show_rules(schain_name: str) -> None:
prompt='Are you sure? Repair mode may corrupt working SKALE chain data.')
@click.option(
'--snapshot-from',
type=IP_TYPE,
type=URL_TYPE,
default=None,
hidden=True,
help='Ip of the node from to download snapshot from'
Expand Down
68 changes: 63 additions & 5 deletions node_cli/cli/sync_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from typing import Optional

import click

from node_cli.core.node import init_sync, update_sync
from node_cli.core.node import init_sync, update_sync, repair_sync
from node_cli.utils.helper import (
abort_if_false,
error_exit,
safe_load_texts,
streamed_cmd,
error_exit
URL_TYPE
)
from node_cli.utils.exit_codes import CLIExitCodes

Expand Down Expand Up @@ -60,21 +63,76 @@ def sync_node():
help=TEXTS['init']['historic_state'],
is_flag=True
)
@click.option(
'--snapshot-from',
type=URL_TYPE,
default=None,
hidden=True,
help='Ip of the node from to download snapshot from'
)
@streamed_cmd
def _init_sync(env_file, archive, catchup, historic_state):
def _init_sync(env_file, archive, catchup, historic_state, snapshot_from: Optional[str]):
if historic_state and not archive:
error_exit(
'--historic-state can be used only is combination with --archive',
exit_code=CLIExitCodes.FAILURE
)
init_sync(env_file, archive, catchup, historic_state)
init_sync(env_file, archive, catchup, historic_state, snapshot_from)


@sync_node.command('update', help='Update sync node from .env file')
@click.option('--yes', is_flag=True, callback=abort_if_false,
expose_value=False,
prompt='Are you sure you want to update SKALE node software?')
@click.option(
'--unsafe',
'unsafe_ok',
help='Allow unsafe update',
hidden=True,
is_flag=True
)
@click.argument('env_file')
@streamed_cmd
def _update_sync(env_file):
def _update_sync(env_file, unsafe_ok):
update_sync(env_file)


@sync_node.command('repair', help='Start sync node from empty database')
@click.option('--yes', is_flag=True, callback=abort_if_false,
expose_value=False,
prompt='Are you sure you want to start sync node from empty database?')
@click.option(
'--archive',
help=TEXTS['init']['archive'],
is_flag=True
)
@click.option(
'--catchup',
help=TEXTS['init']['catchup'],
is_flag=True
)
@click.option(
'--historic-state',
help=TEXTS['init']['historic_state'],
is_flag=True
)
@click.option(
'--snapshot-from',
type=URL_TYPE,
default=None,
hidden=True,
help='Ip of the node from to download snapshot from'
)
@streamed_cmd
def _repair_sync(
archive: str,
catchup: str,
historic_state: str,
snapshot_from: Optional[str] = None
) -> None:
repair_sync(
archive=archive,
catchup=catchup,
historic_state=historic_state,
snapshot_from=snapshot_from
)
1 change: 1 addition & 0 deletions node_cli/configs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

NODE_DATA_PATH = os.path.join(SKALE_DIR, 'node_data')
SCHAIN_NODE_DATA_PATH = os.path.join(NODE_DATA_PATH, 'schains')
NODE_CLI_STATUS_FILENAME = 'node_cli.status'
NODE_CONFIG_PATH = os.path.join(NODE_DATA_PATH, 'node_config.json')
CONTAINER_CONFIG_PATH = os.path.join(SKALE_DIR, 'config')
CONTAINER_CONFIG_TMP_PATH = os.path.join(SKALE_TMP_DIR, 'config')
Expand Down
30 changes: 23 additions & 7 deletions node_cli/configs/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,22 @@

ROUTES = {
'v1': {
'node': ['info', 'register', 'maintenance-on', 'maintenance-off', 'signature',
'send-tg-notification', 'exit/start', 'exit/status', 'set-domain-name'],
'node': [
'info',
'register',
'maintenance-on',
'maintenance-off',
'signature',
'send-tg-notification',
'exit/start',
'exit/status',
'set-domain-name',
'update-safe',
],
'health': ['containers', 'schains', 'sgx'],
'schains': ['config', 'list', 'dkg-statuses', 'firewall-rules', 'repair', 'get'],
'ssl': ['status', 'upload'],
'wallet': ['info', 'send-eth']
'wallet': ['info', 'send-eth'],
}
}

Expand All @@ -40,8 +50,11 @@ class RouteNotFoundException(Exception):


def route_exists(blueprint, method, api_version):
return ROUTES.get(api_version) and ROUTES[api_version].get(blueprint) and \
method in ROUTES[api_version][blueprint]
return (
ROUTES.get(api_version)
and ROUTES[api_version].get(blueprint)
and method in ROUTES[api_version][blueprint]
)


def get_route(blueprint, method, api_version=CURRENT_API_VERSION, check=True):
Expand All @@ -53,5 +66,8 @@ def get_route(blueprint, method, api_version=CURRENT_API_VERSION, check=True):

def get_all_available_routes(api_version=CURRENT_API_VERSION):
routes = ROUTES[api_version]
return [get_route(blueprint, method, api_version) for blueprint in routes
for method in routes[blueprint]]
return [
get_route(blueprint, method, api_version)
for blueprint in routes
for method in routes[blueprint]
]
51 changes: 46 additions & 5 deletions node_cli/core/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
turn_on_op,
restore_op,
init_sync_op,
repair_sync_op,
update_sync_op
)
from node_cli.utils.print_formatters import (
Expand Down Expand Up @@ -92,6 +93,16 @@ class NodeStatuses(Enum):
NOT_CREATED = 5


def is_update_safe() -> bool:
status, payload = get_request(BLUEPRINT_NAME, 'update-safe')
if status == 'error':
return False
safe = payload['update_safe']
if not safe:
logger.info('Locked schains: %s', payload['unsafe_chains'])
return safe


@check_inited
@check_user
def register_node(name, p2p_ip,
Expand Down Expand Up @@ -176,7 +187,8 @@ def init_sync(
env_filepath: str,
archive: bool,
catchup: bool,
historic_state: bool
historic_state: bool,
snapshot_from: str
) -> None:
configure_firewall_rules()
env = get_node_env(env_filepath, sync_node=True)
Expand All @@ -187,7 +199,8 @@ def init_sync(
env,
archive,
catchup,
historic_state
historic_state,
snapshot_from
)
if not inited_ok:
error_exit(
Expand All @@ -206,7 +219,7 @@ def init_sync(

@check_inited
@check_user
def update_sync(env_filepath):
def update_sync(env_filepath: str, unsafe_ok: bool = False) -> None:
logger.info('Node update started')
configure_firewall_rules()
env = get_node_env(env_filepath, sync_node=True)
Expand All @@ -222,6 +235,27 @@ def update_sync(env_filepath):
logger.info('Node update finished')


@check_inited
@check_user
def repair_sync(
archive: bool,
catchup: bool,
historic_state: bool,
snapshot_from: str
) -> None:

env_params = extract_env_params(INIT_ENV_FILEPATH, sync_node=True)
schain_name = env_params['SCHAIN_NAME']
repair_sync_op(
schain_name=schain_name,
archive=archive,
catchup=catchup,
historic_state=historic_state,
snapshot_from=snapshot_from
)
logger.info('Schain was started from scratch')


def get_node_env(
env_filepath,
inited_node=False,
Expand Down Expand Up @@ -259,7 +293,11 @@ def get_node_env(

@check_inited
@check_user
def update(env_filepath, pull_config_for_schain):
def update(env_filepath: str, pull_config_for_schain: str, unsafe_ok: bool = False) -> None:
if not unsafe_ok and not is_update_safe():
error_msg = 'Cannot update safely'
error_exit(error_msg, exit_code=CLIExitCodes.UNSAFE_UPDATE)

logger.info('Node update started')
configure_firewall_rules()
env = get_node_env(
Expand Down Expand Up @@ -388,7 +426,10 @@ def set_maintenance_mode_off():

@check_inited
@check_user
def turn_off(maintenance_on):
def turn_off(maintenance_on: bool = False, unsafe_ok: bool = False) -> None:
if not unsafe_ok and not is_update_safe():
error_msg = 'Cannot turn off safely'
error_exit(error_msg, exit_code=CLIExitCodes.UNSAFE_UPDATE)
if maintenance_on:
set_maintenance_mode_on()
turn_off_op()
Expand Down
Loading
Loading