diff --git a/modules/__init__.py b/modules/__init__.py index 3d09bb9e..076e12d0 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -61,6 +61,7 @@ class Setting: 'ChatId': Setting('alert-bot', None, 'Alerting Telegram chat id'), 'auto_backup': Setting('validator', None, 'Make validator backup every election'), 'auto_backup_path': Setting('validator', '/tmp/mytoncore/auto_backups/', 'Path to store auto-backups'), + 'onlyNode': Setting(None, None, 'MyTonCtrl will work only for collecting validator telemetry (if `sendTelemetry` is True), without participating in Elections and etc.') } diff --git a/modules/alert_bot.py b/modules/alert_bot.py index 2ebf4034..b1c1d13c 100644 --- a/modules/alert_bot.py +++ b/modules/alert_bot.py @@ -142,7 +142,7 @@ def init(self): from modules.validator import ValidatorModule self.validator_module = ValidatorModule(self.ton, self.local) self.hostname = get_hostname() - self.ip = self.ton.get_validator_engine_ip() + self.ip = self.ton.get_node_ip() self.set_global_vars() self.inited = True diff --git a/modules/backups.py b/modules/backups.py index 7ed70954..0458c298 100644 --- a/modules/backups.py +++ b/modules/backups.py @@ -27,6 +27,11 @@ def create_tmp_ton_dir(self): self.create_keyring(dir_name_db) return dir_name + @staticmethod + def run_create_backup(args): + backup_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/create_backup.sh') + return subprocess.run(["bash", backup_script_path] + args, timeout=5) + def create_backup(self, args): if len(args) > 1: color_print("{red}Bad args. Usage:{endc} create_backup [filename]") @@ -35,8 +40,7 @@ def create_backup(self, args): command_args = ["-m", self.ton.local.buffer.my_work_dir, "-t", tmp_dir] if len(args) == 1: command_args += ["-d", args[0]] - backup_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/create_backup.sh') - process = subprocess.run(["bash", backup_script_path] + command_args, timeout=5) + process = self.run_create_backup(command_args) if process.returncode == 0: color_print("create_backup - {green}OK{endc}") @@ -46,6 +50,11 @@ def create_backup(self, args): return process.returncode # end define + @staticmethod + def run_restore_backup(args): + restore_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/restore_backup.sh') + return run_as_root(["bash", restore_script_path] + args) + def restore_backup(self, args): if len(args) == 0 or len(args) > 2: color_print("{red}Bad args. Usage:{endc} restore_backup [-y]") @@ -67,8 +76,7 @@ def restore_backup(self, args): ip = str(ip2int(get_own_ip())) command_args = ["-m", self.ton.local.buffer.my_work_dir, "-n", args[0], "-i", ip] - restore_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/restore_backup.sh') - if run_as_root(["bash", restore_script_path] + command_args) == 0: + if self.run_restore_backup(command_args) == 0: color_print("restore_backup - {green}OK{endc}") self.local.exit() else: diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 0dd136ff..00936ca9 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -551,8 +551,14 @@ def General(local): # scanner.Run() # Start threads - local.start_cycle(Elections, sec=600, args=(local, ton, )) local.start_cycle(Statistics, sec=10, args=(local, )) + local.start_cycle(Telemetry, sec=60, args=(local, ton, )) + local.start_cycle(OverlayTelemetry, sec=7200, args=(local, ton, )) + if local.db.get("onlyNode"): # mytoncore service works only for telemetry + thr_sleep() + return + + local.start_cycle(Elections, sec=600, args=(local, ton, )) local.start_cycle(Offers, sec=600, args=(local, ton, )) local.start_cycle(save_past_events, sec=300, args=(local, ton, )) @@ -562,8 +568,6 @@ def General(local): local.start_cycle(Complaints, sec=t, args=(local, ton, )) local.start_cycle(Slashing, sec=t, args=(local, ton, )) - local.start_cycle(Telemetry, sec=60, args=(local, ton, )) - local.start_cycle(OverlayTelemetry, sec=7200, args=(local, ton, )) local.start_cycle(ScanLiteServers, sec=60, args=(local, ton,)) from modules.custom_overlays import CustomOverlayModule diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 6896bf79..93f16f0a 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3820,13 +3820,16 @@ def GetNetworkName(self): return "unknown" #end define - def get_validator_engine_ip(self): + def get_node_ip(self): try: config = self.GetValidatorConfig() return int2ip(config['addrs'][0]['ip']) except: return None + def get_validator_engine_ip(self): + return self.validatorConsole.addr.split(':')[0] + def GetFunctionBuffer(self, name, timeout=10): timestamp = get_timestamp() buff = self.local.buffer.get(name) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 3263b3b2..7b939e0c 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -762,6 +762,11 @@ def PrintLocalStatus(local, ton, adnlAddr, validatorIndex, validatorEfficiency, validatorVersion_text = local.translate("local_status_version_validator").format(validatorGitHash_text, validatorGitBranch_text) color_print(local.translate("local_status_head")) + node_ip = ton.get_validator_engine_ip() + is_node_remote = node_ip != '127.0.0.1' + if is_node_remote: + nodeIpAddr_text = local.translate("node_ip_address").format(node_ip) + color_print(nodeIpAddr_text) if ton.using_validator(): print(validatorIndex_text) # print(validatorEfficiency_text) @@ -776,7 +781,8 @@ def PrintLocalStatus(local, ton, adnlAddr, validatorIndex, validatorEfficiency, print(disksLoad_text) print(mytoncoreStatus_text) - print(validatorStatus_text) + if not is_node_remote: + print(validatorStatus_text) print(validator_out_of_sync_text) print(validator_out_of_ser_text) print(dbStatus_text) diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index 83752783..ee3f900f 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -249,6 +249,11 @@ "ru": "{cyan}===[ Статус ноды ]==={endc}", "zh_TW": "{cyan}===[ 节点狀態 ]==={endc}" }, + "node_ip_address": { + "en": "Node IP address: {{bold}}{0}{{endc}}", + "ru": "IP адрес Ноды: {{bold}}{0}{{endc}}", + "zh_TW": "節點 IP 地址: {{bold}}{0}{{endc}}" + }, "local_status_validator_index": { "en": "Validator index: {0}", "ru": "Индекс валидатора: {0}", diff --git a/mytonctrl/scripts/restore_backup.sh b/mytonctrl/scripts/restore_backup.sh index ca53f0de..005ee7d8 100644 --- a/mytonctrl/scripts/restore_backup.sh +++ b/mytonctrl/scripts/restore_backup.sh @@ -1,13 +1,15 @@ name="backup.tar.gz" mtc_dir="$HOME/.local/share/mytoncore" ip=0 +user=$(logname) # Get arguments -while getopts n:m:i: flag +while getopts n:m:i:u: flag do case "${flag}" in n) name=${OPTARG};; m) mtc_dir=${OPTARG};; i) ip=${OPTARG};; + u) user=${OPTARG};; *) echo "Flag -${flag} is not recognized. Aborting" exit 1 ;; @@ -38,9 +40,13 @@ if [ ! -d ${tmp_dir}/db ]; then fi rm -rf /var/ton-work/db/keyring -cp -rf ${tmp_dir}/db /var/ton-work -cp -rf ${tmp_dir}/keys /var/ton-work -cp -rfT ${tmp_dir}/mytoncore $mtc_dir + +chown -R $user:$user ${tmp_dir}/mytoncore +chown -R $user:$user ${tmp_dir}/keys + +cp -rfp ${tmp_dir}/db /var/ton-work +cp -rfp ${tmp_dir}/keys /var/ton-work +cp -rfpT ${tmp_dir}/mytoncore $mtc_dir chown -R validator:validator /var/ton-work/db/keyring @@ -48,9 +54,14 @@ echo -e "${COLOR}[2/4]${ENDC} Extracted files from archive" rm -r /var/ton-work/db/dht-* -python3 -c "import json;path='/var/ton-work/db/config.json';f=open(path);d=json.load(f);f.close();d['addrs'][0]['ip']=int($ip);f=open(path, 'w');f.write(json.dumps(d, indent=4));f.close()" +if [ $ip -ne 0 ]; then + echo "Replacing IP in node config" + python3 -c "import json;path='/var/ton-work/db/config.json';f=open(path);d=json.load(f);f.close();d['addrs'][0]['ip']=int($ip);f=open(path, 'w');f.write(json.dumps(d, indent=4));f.close()" +else + echo "IP is not provided, skipping IP replacement" +fi -echo -e "${COLOR}[3/4]${ENDC} Deleted DHT files, replaced IP in node config" +echo -e "${COLOR}[3/4]${ENDC} Deleted DHT files" systemctl start validator systemctl start mytoncore diff --git a/mytoninstaller/config.py b/mytoninstaller/config.py index 83039853..1be86b79 100644 --- a/mytoninstaller/config.py +++ b/mytoninstaller/config.py @@ -44,6 +44,8 @@ def backup_config(local, config_path): def BackupVconfig(local): + if local.buffer.only_mtc: + return local.add_log("Backup validator config file 'config.json' to 'config.json.backup'", "debug") vconfig_path = local.buffer.vconfig_path backupPath = vconfig_path + ".backup" diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 270afe97..cb0dffec 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -30,7 +30,7 @@ enable_ls_proxy, enable_ton_storage, enable_ton_storage_provider, - EnableMode + EnableMode, ConfigureFromBackup, ConfigureOnlyNode ) from mytoninstaller.config import ( CreateLocalConfig, @@ -276,6 +276,17 @@ def General(local, console): mx = sys.argv.index("-m") mode = sys.argv[mx+1] local.buffer.mode = mode + if "--only-mtc" in sys.argv: + ox = sys.argv.index("--only-mtc") + local.buffer.only_mtc = str2bool(sys.argv[ox+1]) + if "--only-node" in sys.argv: + ox = sys.argv.index("--only-node") + local.buffer.only_node = str2bool(sys.argv[ox+1]) + if "--backup" in sys.argv: + bx = sys.argv.index("--backup") + backup = sys.argv[bx+1] + if backup != "none": + local.buffer.backup = backup #end if FirstMytoncoreSettings(local) @@ -286,6 +297,8 @@ def General(local, console): BackupMconfig(local) CreateSymlinks(local) EnableMode(local) + ConfigureFromBackup(local) + ConfigureOnlyNode(local) #end define diff --git a/mytoninstaller/settings.py b/mytoninstaller/settings.py index cba219ea..43dafd3f 100644 --- a/mytoninstaller/settings.py +++ b/mytoninstaller/settings.py @@ -14,7 +14,7 @@ run_as_root, color_print, ip2int, - Dict + Dict, int2ip ) from mytoninstaller.utils import StartValidator, StartMytoncore, start_service, stop_service, get_ed25519_pubkey from mytoninstaller.config import SetConfig, GetConfig, get_own_ip, backup_config @@ -22,6 +22,9 @@ def FirstNodeSettings(local): + if local.buffer.only_mtc: + return + local.add_log("start FirstNodeSettings fuction", "debug") # Создать переменные @@ -198,6 +201,8 @@ def FirstMytoncoreSettings(local): #end define def EnableValidatorConsole(local): + if local.buffer.only_mtc: + return local.add_log("start EnableValidatorConsole function", "debug") # Create variables @@ -300,6 +305,9 @@ def EnableValidatorConsole(local): #end define def EnableLiteServer(local): + if local.buffer.only_mtc: + return + local.add_log("start EnableLiteServer function", "debug") # Create variables @@ -906,9 +914,70 @@ def CreateSymlinks(local): def EnableMode(local): args = ["python3", "-m", "mytoncore", "-e"] - if local.buffer.mode: + if local.buffer.mode and local.buffer.mode != "none": args.append("enable_mode_" + local.buffer.mode) else: return args = ["su", "-l", local.buffer.user, "-c", ' '.join(args)] subprocess.run(args) + + +def set_external_ip(local, ip): + mconfig_path = local.buffer.mconfig_path + + mconfig = GetConfig(path=mconfig_path) + + mconfig.liteClient.liteServer.ip = ip + mconfig.validatorConsole.addr = f'{ip}:{mconfig.validatorConsole.addr.split(":")[1]}' + + # write mconfig + local.add_log("write mconfig", "debug") + SetConfig(path=mconfig_path, data=mconfig) + + +def ConfigureFromBackup(local): + if not local.buffer.backup: + return + from modules.backups import BackupModule + mconfig_path = local.buffer.mconfig_path + mconfig_dir = get_dir_from_path(mconfig_path) + local.add_log("start ConfigureFromBackup function", "info") + backup_file = local.buffer.backup + + os.makedirs(local.buffer.ton_work_dir, exist_ok=True) + if not local.buffer.only_mtc: + ip = str(ip2int(get_own_ip())) + BackupModule.run_restore_backup(["-m", mconfig_dir, "-n", backup_file, "-i", ip]) + + if local.buffer.only_mtc: + BackupModule.run_restore_backup(["-m", mconfig_dir, "-n", backup_file]) + local.add_log("Installing only mtc", "info") + vconfig_path = local.buffer.vconfig_path + vconfig = GetConfig(path=vconfig_path) + try: + node_ip = int2ip(vconfig['addrs'][0]['ip']) + except: + local.add_log("Can't get ip from validator", "error") + return + set_external_ip(local, node_ip) + + +def ConfigureOnlyNode(local): + if not local.buffer.only_node: + return + from modules.backups import BackupModule + mconfig_path = local.buffer.mconfig_path + mconfig_dir = get_dir_from_path(mconfig_path) + local.add_log("start ConfigureOnlyNode function", "info") + + process = BackupModule.run_create_backup(["-m", mconfig_dir, ]) + if process.returncode != 0: + local.add_log("Backup creation failed", "error") + return + local.add_log("Backup successfully created. Use this file on the controller server with `--only-mtc` flag on installation.", "info") + + mconfig = GetConfig(path=mconfig_path) + mconfig.onlyNode = True + SetConfig(path=mconfig_path, data=mconfig) + + start_service(local, 'mytoncore') diff --git a/scripts/install.sh b/scripts/install.sh index 1da6e42c..68abf777 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -32,6 +32,9 @@ show_help_and_exit() { echo ' -n NETWORK Specify the network (mainnet or testnet)' echo ' -v VERSION Specify the ton node version (commit, branch, or tag)' echo ' -u USER Specify the user to be used for MyTonCtrl installation' + echo ' -p PATH Provide backup file for MyTonCtrl installation' + echo ' -o Install only MyTonCtrl. Must be used with -p' + echo ' -l Install only TON node' echo ' -h Show this help' exit } @@ -45,10 +48,14 @@ config="https://ton-blockchain.github.io/global.config.json" telemetry=true ignore=false dump=false +only_mtc=false +only_node=false +backup=none +mode=none cpu_required=16 mem_required=64000000 # 64GB in KB -while getopts ":c:tida:r:b:m:n:v:u:h" flag; do +while getopts ":c:tidola:r:b:m:n:v:u:p:h" flag; do case "${flag}" in c) config=${OPTARG};; t) telemetry=false;; @@ -61,6 +68,9 @@ while getopts ":c:tida:r:b:m:n:v:u:h" flag; do n) network=${OPTARG};; v) ton_node_version=${OPTARG};; u) user=${OPTARG};; + o) only_mtc=true;; + l) only_node=true;; + p) backup=${OPTARG};; h) show_help_and_exit;; *) echo "Flag -${flag} is not recognized. Aborting" @@ -69,7 +79,13 @@ while getopts ":c:tida:r:b:m:n:v:u:h" flag; do done -if [ "${mode}" = "" ]; then # no mode +if [ "$only_mtc" = true ] && [ "$backup" = "none" ]; then + echo "Backup file must be provided if only mtc installation" + exit 1 +fi + + +if [ "${mode}" = "none" ] && [ "$backup" = "none" ]; then # no mode or backup was provided echo "Running cli installer" wget https://raw.githubusercontent.com/${author}/${repo}/${branch}/scripts/install.py pip3 install inquirer==3.4.0 @@ -144,7 +160,7 @@ if [ "${user}" = "" ]; then # no user fi fi echo "User: $user" -python3 -m mytoninstaller -u ${user} -t ${telemetry} --dump ${dump} -m ${mode} +python3 -m mytoninstaller -u ${user} -t ${telemetry} --dump ${dump} -m ${mode} --only-mtc ${only_mtc} --backup ${backup} --only-node ${only_node} # set migrate version migrate_version=1 diff --git a/scripts/ton_installer.sh b/scripts/ton_installer.sh index 6454fd2a..5dc962cf 100644 --- a/scripts/ton_installer.sh +++ b/scripts/ton_installer.sh @@ -118,8 +118,10 @@ if [ "${ton_node_version}" != "master" ]; then cd ../ fi +cd $SOURCES_DIR/ton git submodule sync --recursive git submodule update +cd ../ git config --global --add safe.directory $SOURCES_DIR/ton