diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index e728ef72..33eb35f2 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -40,6 +40,18 @@ from functools import partial +def init_envs(local): + local.buffer.cport = int(os.getenv('VALIDATOR_CONSOLE_PORT', random.randint(2000, 65000))) + local.buffer.lport = int(os.getenv('LITESERVER_PORT', random.randint(2000, 65000))) + local.buffer.vport = int(os.getenv('VALIDATOR_PORT', random.randint(2000, 65000))) + local.buffer.archive_ttl = os.getenv('ARCHIVE_TTL') + local.buffer.state_ttl = os.getenv('STATE_TTL') + local.buffer.public_ip = os.getenv('PUBLIC_IP') + local.buffer.add_shard = os.getenv('ADD_SHARD') + local.buffer.archive_blocks = os.getenv('ARCHIVE_BLOCKS') + local.buffer.collate_shard = os.getenv('COLLATE_SHARD', '') + + def Init(local, console): local.db.config.isStartOnlyOneProcess = False local.db.config.logLevel = "debug" @@ -51,9 +63,7 @@ def Init(local, console): # create variables local.buffer.user = get_current_user() local.buffer.vuser = "validator" - local.buffer.cport = int(os.getenv('VALIDATOR_CONSOLE_PORT', random.randint(2000, 65000))) - local.buffer.lport = int(os.getenv('LITESERVER_PORT', random.randint(2000, 65000))) - local.buffer.vport = int(os.getenv('VALIDATOR_PORT', random.randint(2000, 65000))) + init_envs(local) # this funciton injects MyPyClass instance def inject_globals(func): diff --git a/mytoninstaller/settings.py b/mytoninstaller/settings.py index 648094f0..71acfab7 100644 --- a/mytoninstaller/settings.py +++ b/mytoninstaller/settings.py @@ -47,13 +47,13 @@ def FirstNodeSettings(local): vconfig_path = local.buffer.vconfig_path vport = local.buffer.vport - if os.getenv('ARCHIVE_TTL'): - archive_ttl = int(os.getenv('ARCHIVE_TTL')) + if local.buffer.archive_ttl is not None: + archive_ttl = int(local.buffer.archive_ttl) else: archive_ttl = 2592000 if local.buffer.mode == 'liteserver' else 86400 state_ttl = None - if os.getenv('STATE_TTL'): - state_ttl = int(os.getenv('STATE_TTL')) + if local.buffer.state_ttl is not None: + state_ttl = int(local.buffer.state_ttl) archive_ttl -= state_ttl if archive_ttl == 0: archive_ttl = 1 # todo: remove this when archive_ttl==0 will be allowed in node @@ -93,16 +93,16 @@ def FirstNodeSettings(local): cmd = f"{validatorAppPath} --threads {cpus} --daemonize --global-config {globalConfigPath} --db {ton_db_dir} --logname {tonLogPath} --verbosity 1" cmd += ttl_cmd - if os.getenv('ADD_SHARD'): - add_shard = os.getenv('ADD_SHARD') + if local.buffer.add_shard is not None: + add_shard = local.buffer.add_shard cmd += f' -M' for shard in add_shard.split(): cmd += f' --add-shard {shard}' add2systemd(name="validator", user=vuser, start=cmd, pre='/bin/sleep 2') # post="/usr/bin/python3 /usr/src/mytonctrl/mytoncore.py -e \"validator down\"" - if os.getenv('PUBLIC_IP'): - ip = os.getenv('PUBLIC_IP') + if local.buffer.public_ip is not None: + ip = local.buffer.public_ip else: ip = get_own_ip() addr = "{ip}:{vport}".format(ip=ip, vport=vport) @@ -204,13 +204,13 @@ def parse_block_value(local, block: str): def download_archive_from_ts(local): - archive_blocks = os.getenv('ARCHIVE_BLOCKS') + if local.buffer.archive_blocks is None: + return + archive_blocks = local.buffer.archive_blocks downloads_path = '/var/ton-work/ts-downloads/' os.makedirs(downloads_path, exist_ok=True) subprocess.run(["chmod", "o+wx", downloads_path]) - if archive_blocks is None: - return block_from, block_to = archive_blocks, None if len(archive_blocks.split()) > 1: block_from, block_to = archive_blocks.split() @@ -1189,7 +1189,7 @@ def SetInitialSync(local): def SetupCollator(local): if local.buffer.mode != "collator": return - shards = os.getenv('COLLATE_SHARD', '').split() + shards = local.buffer.collate_shard.split() if not shards: shards = ['0:8000000000000000'] local.add_log(f"Setting up collator for shards: {shards}", "info") diff --git a/scripts/install.py b/scripts/install.py index 81f4e41c..324e18cb 100644 --- a/scripts/install.py +++ b/scripts/install.py @@ -211,15 +211,15 @@ def run_install(answers: dict): args += f' -c {config}' if archive_ttl: - os.environ['ARCHIVE_TTL'] = archive_ttl # set env variable + CONFIG['ARCHIVE_TTL'] = archive_ttl # set env variable if state_ttl: - os.environ['STATE_TTL'] = state_ttl + CONFIG['STATE_TTL'] = state_ttl if add_shard: - os.environ['ADD_SHARD'] = add_shard + CONFIG['ADD_SHARD'] = add_shard if collate_shard: - os.environ['COLLATE_SHARD'] = collate_shard + CONFIG['COLLATE_SHARD'] = collate_shard if archive_blocks: - os.environ['ARCHIVE_BLOCKS'] = archive_blocks + CONFIG['ARCHIVE_BLOCKS'] = archive_blocks command += ['-v', 'master'] if validator_mode and validator_mode not in ('Skip', 'Validator wallet'): @@ -239,7 +239,7 @@ def run_install(answers: dict): log = None stdin = None if background: - os.environ['PYTHONUNBUFFERED'] = '1' + CONFIG['PYTHONUNBUFFERED'] = '1' log = open("mytonctrl_installation.log", "a") stdin=subprocess.DEVNULL command = ['nohup'] + command @@ -249,6 +249,19 @@ def run_install(answers: dict): print(command) + if os.getenv('PRINT_ENV'): + print('command:') + print(' '.join(command)) + print('envs:') + for k, v in CONFIG.items(): + if ' ' in v: + v = f'"{v}"' + print(f'{k}={v}') + sys.exit(0) + + for k, v in CONFIG.items(): + os.environ[k] = v + process = subprocess.Popen( command, stdout=log, @@ -261,6 +274,9 @@ def run_install(answers: dict): print("="*100 + f"\nRunning installation in the background. Check './mytonctrl_installation.log' for progress. PID: {process.pid}\n" + "="*100) +CONFIG = {} + + def main(): try: answers = run_cli() diff --git a/scripts/install.sh b/scripts/install.sh index abd5af18..87de506b 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -22,22 +22,24 @@ config_overridden=false show_help_and_exit() { echo 'Supported arguments:' - echo ' -c PATH Provide custom config for toninstaller.sh' - echo ' -t Disable telemetry' - echo ' -i Ignore minimum requirements' - echo ' -d Use pre-packaged dump. Reduces duration of initial synchronization.' - echo ' -a Set MyTonCtrl git repo author' - echo ' -r Set MyTonCtrl git repo' - echo ' -b Set MyTonCtrl git repo branch' - echo ' -g URL TON node git repo URL (default: https://github.com/ton-blockchain/ton.git)' - echo ' -m MODE Install MyTonCtrl with specified mode (validator or liteserver)' - 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' + echo ' -c, --config URL Provide custom network config' + echo ' -e, --env-file PATH Provide env file with installation parameters' + echo ' --print-env Print result command and envs after interactive installer without installing MyTonCtrl' + echo ' -t, --telemetry Disable telemetry' + echo ' -i, --ignore-reqs Ignore minimum requirements' + echo ' -d, --dump Use pre-packaged dump. Reduces duration of initial synchronization' + echo ' -a, --author Set MyTonCtrl git repo author' + echo ' -r, --repo Set MyTonCtrl git repo name' + echo ' -b, --branch Set MyTonCtrl git repo branch' + echo ' -m, --mode MODE Install MyTonCtrl with specified mode (validator or liteserver). Leave empty to launch interactive installer' + echo ' -n, --network NETWORK Specify the network (mainnet or testnet)' + echo ' -g, --node-repo URL TON node git repo URL (default: https://github.com/ton-blockchain/ton.git)' + echo ' -v, --node-version VERSION Specify the TON node version (commit, branch, or tag)' + echo ' -u, --user USER Specify the user to be used for MyTonCtrl installation' + echo ' -p, --backup PATH Provide backup file for MyTonCtrl installation' + echo ' -o, --only-mtc Install only MyTonCtrl. Must be used with -p' + echo ' -l, --only-node Install only TON node' + echo ' -h, --help Show this help' exit } @@ -47,6 +49,7 @@ fi # node install parameters config="https://ton-blockchain.github.io/global.config.json" +env_file="" telemetry=true ignore=false dump=false @@ -57,7 +60,58 @@ mode=none cpu_required=16 mem_required=64000000 # 64GB in KB -while getopts ":c:tidola:r:b:m:n:v:u:p:g:h" flag; do +# transform --long options to short, because getopts only supports short ones + +newargv=() +while (($#)); do + case "$1" in + --) # end of options + shift + newargv+=( -- "$@" ) + break + ;; + + # no arg + --dump) newargv+=(-d) ;; + --only-mtc) newargv+=(-o) ;; + --only-node) newargv+=(-l) ;; + --help) newargv+=(-h) ;; + --telemetry) newargv+=(-t) ;; + --ignore-reqs) newargv+=(-i) ;; + --print-env) export PRINT_ENV=true ;; + + # with arg + --config|--author|--repo|--branch|--mode|--network|--node-repo|--backup|--user|--node-version|--env-file) + if (($# < 2)); then + echo "Error: option $1 requires value" >&2; exit 2 + fi + case "$1" in + --config) newargv+=(-c "$2") ;; + --author) newargv+=(-a "$2") ;; + --repo) newargv+=(-r "$2") ;; + --branch) newargv+=(-b "$2") ;; + --mode) newargv+=(-m "$2") ;; + --network) newargv+=(-n "$2") ;; + --node-repo) newargv+=(-g "$2") ;; + --backup) newargv+=(-p "$2") ;; + --user) newargv+=(-u "$2") ;; + --node-version) newargv+=(-v "$2") ;; + --env-file) newargv+=(-e "$2") ;; + esac + shift ;; + --*) + echo "Error: unknown option '$1'" >&2; exit 2 ;; + *) + newargv+=("$1") ;; + esac + shift +done + +#printf ' %q' "${newargv[@]}" +#printf '\n' +set -- "${newargv[@]}" + +while getopts ":c:tidola:r:b:m:n:v:u:p:g:e:h" flag; do case "${flag}" in c) config=${OPTARG}; config_overridden=true;; t) telemetry=false;; @@ -74,6 +128,7 @@ while getopts ":c:tidola:r:b:m:n:v:u:p:g:h" flag; do o) only_mtc=true;; l) only_node=true;; p) backup=${OPTARG};; + e) env_file=${OPTARG};; h) show_help_and_exit;; *) echo "Flag -${flag} is not recognized. Aborting" @@ -81,6 +136,15 @@ while getopts ":c:tidola:r:b:m:n:v:u:p:g:h" flag; do esac done +if [ -n "$env_file" ]; then + if [ ! -f "$env_file" ]; then + echo "Env file not found, aborting." + exit 1 + fi + set -a + source "$env_file" + set +a +fi if [ "$only_mtc" = true ] && [ "$backup" = "none" ]; then echo "Backup file must be provided if only mtc installation"