Skip to content

Commit

Permalink
Merge pull request #699 from skalenetwork/snapshot-from-repair
Browse files Browse the repository at this point in the history
Snapshot from repair
  • Loading branch information
dmytrotkk authored Feb 9, 2023
2 parents 195bd7c + 7cb067c commit e1337e7
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 75 deletions.
59 changes: 6 additions & 53 deletions node_cli/cli/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@
# 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/>.

import ipaddress
from typing import Optional
from urllib.parse import urlparse

import click

from node_cli.core.node import (
Expand All @@ -45,7 +41,8 @@
from node_cli.utils.helper import (
abort_if_false,
safe_load_texts,
streamed_cmd
streamed_cmd,
IP_TYPE
)
from node_cli.utils.meta import get_meta_info
from node_cli.utils.print_formatters import print_meta_info
Expand All @@ -54,36 +51,6 @@
TEXTS = safe_load_texts()


class UrlType(click.ParamType):
name = 'url'

def convert(self, value, param, ctx):
try:
result = urlparse(value)
except ValueError:
self.fail(f'Some characters are not allowed in {value}',
param, ctx)
if not all([result.scheme, result.netloc]):
self.fail(f'Expected valid url. Got {value}', param, ctx)
return value


class IpType(click.ParamType):
name = 'ip'

def convert(self, value, param, ctx):
try:
ipaddress.ip_address(value)
except ValueError:
self.fail(f'expected valid ipv4/ipv6 address. Got {value}',
param, ctx)
return value


URL_TYPE = UrlType()
IP_TYPE = IpType()


@click.group()
def node_cli():
pass
Expand Down Expand Up @@ -132,33 +99,19 @@ def register_node(name, ip, port, domain):

@node.command('init', help="Initialize SKALE node")
@click.argument('env_file')
@click.option(
'--snapshot-from',
type=IP_TYPE,
default=None,
hidden=True,
help='Ip of the node from to download snapshot from'
)
@streamed_cmd
def init_node(env_file, snapshot_from: Optional[str] = None):
init(env_file, snapshot_from)
def init_node(env_file):
init(env_file)


@node.command('update', help='Update 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.argument('env_file')
@click.option(
'--snapshot-from',
type=IP_TYPE,
default=None,
hidden=True,
help='Ip of the node from to download snapshot from'
)
@streamed_cmd
def update_node(env_file, snapshot_from: Optional[str] = None):
update(env_file, snapshot_from)
def update_node(env_file):
update(env_file)


@node.command('signature', help='Get node signature for given validator id')
Expand Down
15 changes: 12 additions & 3 deletions node_cli/cli/schains.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
# 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.utils.helper import abort_if_false
from node_cli.utils.helper import abort_if_false, IP_TYPE
from node_cli.core.schains import (
describe,
get_schain_firewall_rules,
Expand Down Expand Up @@ -72,8 +74,15 @@ def show_rules(schain_name: str) -> None:
@click.option('--yes', is_flag=True, callback=abort_if_false,
expose_value=False,
prompt='Are you sure? Repair mode may corrupt working SKALE chain data.')
def repair(schain_name: str) -> None:
toggle_schain_repair_mode(schain_name)
@click.option(
'--snapshot-from',
type=IP_TYPE,
default=None,
hidden=True,
help='Ip of the node from to download snapshot from'
)
def repair(schain_name: str, snapshot_from: Optional[str] = None) -> None:
toggle_schain_repair_mode(schain_name, snapshot_from=snapshot_from)


@schains.command('info', help='Show info about schain')
Expand Down
8 changes: 4 additions & 4 deletions node_cli/core/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,12 @@ def register_node(name, p2p_ip,


@check_not_inited
def init(env_filepath, snapshot_from: Optional[str] = None):
def init(env_filepath):
env = get_node_env(env_filepath)
if env is None:
return
configure_firewall_rules()
inited_ok = init_op(env_filepath, env, snapshot_from=snapshot_from)
inited_ok = init_op(env_filepath, env)
if not inited_ok:
error_exit(
'Init operation failed',
Expand Down Expand Up @@ -187,11 +187,11 @@ def get_node_env(env_filepath, inited_node=False, sync_schains=None):

@check_inited
@check_user
def update(env_filepath, snapshot_from: Optional[str] = None):
def update(env_filepath):
logger.info('Node update started')
configure_firewall_rules()
env = get_node_env(env_filepath, inited_node=True, sync_schains=False)
update_ok = update_op(env_filepath, env, snapshot_from=snapshot_from)
update_ok = update_op(env_filepath, env)
if update_ok:
logger.info('Waiting for containers initialization')
time.sleep(TM_INIT_TIMEOUT)
Expand Down
9 changes: 0 additions & 9 deletions node_cli/core/node_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import logging
from typing import Optional

from node_cli.utils.helper import read_json, write_json, init_file
from node_cli.configs.node_options import NODE_OPTIONS_FILEPATH
Expand All @@ -43,13 +42,5 @@ def _set(self, field_name: str, field_value) -> None:
config[field_name] = field_value
write_json(self.filepath, config)

@property
def snapshot_from(self) -> Optional[str]:
return self._get('snapshot_from')

@snapshot_from.setter
def snapshot_from(self, ip: Optional[str]) -> None:
return self._set('snapshot_from', ip)

def all(self) -> dict:
return read_json(self.filepath)
12 changes: 10 additions & 2 deletions node_cli/core/schains.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import logging
import pprint

from typing import Optional

from node_cli.utils.helper import get_request, post_request, error_exit
from node_cli.utils.exit_codes import CLIExitCodes
from node_cli.utils.print_formatters import (
Expand Down Expand Up @@ -68,11 +70,17 @@ def show_config(name: str) -> None:
error_exit(payload, exit_code=CLIExitCodes.BAD_API_RESPONSE)


def toggle_schain_repair_mode(schain: str) -> None:
def toggle_schain_repair_mode(
schain: str,
snapshot_from: Optional[str] = None
) -> None:
json_params = {'schain_name': schain}
if snapshot_from:
json_params.update({'snapshot_from': snapshot_from})
status, payload = post_request(
blueprint=BLUEPRINT_NAME,
method='repair',
json={'schain_name': schain}
json=json_params
)
if status == 'ok':
print('Schain has been set for repair')
Expand Down
5 changes: 1 addition & 4 deletions node_cli/operations/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def wrapper(env_filepath: str, env: Dict, *args, **kwargs):


@checked_host
def update(env_filepath: str, env: Dict, snapshot_from: Optional[str] = None) -> None:
def update(env_filepath: str, env: Dict) -> None:
compose_rm(env)
remove_dynamic_containers()

Expand All @@ -106,9 +106,6 @@ def update(env_filepath: str, env: Dict, snapshot_from: Optional[str] = None) ->
docker_lvmpy_update(env)
generate_nginx_config()

node_options = NodeOptions()
node_options.snapshot_from = snapshot_from

prepare_host(
env_filepath,
env['DISK_MOUNTPOINT'],
Expand Down
32 changes: 32 additions & 0 deletions node_cli/utils/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
# 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/>.

import ipaddress
import json
import os
import re
import sys
from urllib.parse import urlparse

import yaml
import shutil
Expand Down Expand Up @@ -355,3 +357,33 @@ def rsync_dirs(src: str, dest: str) -> None:
logger.info(f'Syncing {dest} with {src}')
run_cmd(['rsync', '-r', f'{src}/', dest])
run_cmd(['rsync', '-r', f'{src}/.git', dest])


class UrlType(click.ParamType):
name = 'url'

def convert(self, value, param, ctx):
try:
result = urlparse(value)
except ValueError:
self.fail(f'Some characters are not allowed in {value}',
param, ctx)
if not all([result.scheme, result.netloc]):
self.fail(f'Expected valid url. Got {value}', param, ctx)
return value


class IpType(click.ParamType):
name = 'ip'

def convert(self, value, param, ctx):
try:
ipaddress.ip_address(value)
except ValueError:
self.fail(f'expected valid ipv4/ipv6 address. Got {value}',
param, ctx)
return value


URL_TYPE = UrlType()
IP_TYPE = IpType()

0 comments on commit e1337e7

Please sign in to comment.