예제 #1
0
def download_binary(net, uname):
    commit = latest_deployed_version(net)
    branch = latest_deployed_release(net)

    if commit:
        print(f'Downloading latest deployed version for {net}')
        download_near_s3(f'nearcore/{uname}/{branch}/{commit}/near',
                         os.path.expanduser(f'~/.nearup/near/{net}/near'))
        download_near_s3(
            f'nearcore/{uname}/{branch}/{commit}/keypair-generator',
            os.path.expanduser(f'~/.nearup/near/{net}/keypair-generator'))
        download_near_s3(
            f'nearcore/{uname}/{branch}/{commit}/genesis-csv-to-json',
            os.path.expanduser(f'~/.nearup/near/{net}/genesis-csv-to-json'))
        subprocess.check_output(
            ['chmod', '+x',
             os.path.expanduser(f'~/.nearup/near/{net}/near')])
        subprocess.check_output([
            'chmod', '+x',
            os.path.expanduser(f'~/.nearup/near/{net}/keypair-generator')
        ])
        subprocess.check_output([
            'chmod', '+x',
            os.path.expanduser(f'~/.nearup/near/{net}/genesis-csv-to-json')
        ])
        with open(os.path.expanduser(f'~/.nearup/near/{net}/version'),
                  'w') as f:
            f.write(commit)
예제 #2
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def show_logs(follow):
    LOGS_FOLDER = os.path.expanduser('~/.nearup/logs')
    if not os.path.exists(NODE_PID):
        print('Node is not running')
        exit(1)

    pid_info = open(NODE_PID).read()
    if 'devnet' in pid_info:
        net = 'devnet'
    elif 'betanet' in pid_info:
        net = 'betanet'
    elif 'testnet' in pid_info:
        net = 'testnet'
    else:
        # TODO: localnet could have several logs, not showing them all but list log files here
        # Maybe better to support `nearup logs node0` usage.
        print(
            f'You are running local net. Logs are in: ~/.nearup/localnet-logs/'
        )
        exit(0)
    command = ['tail']
    if follow:
        command += ['-f']
    command += [os.path.expanduser(f'~/.nearup/logs/{net}.log')]
    try:
        subprocess.run(command, start_new_session=True)
    except KeyboardInterrupt:
        exit(0)
예제 #3
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def download_binary(net, uname):
    latest_deploy_version = binary_changed(net)
    if latest_deploy_version:
        print(f'Downloading latest deployed version for {net}')
        download_near_s3(
            f'nearcore/{uname}/{net_to_branch(net)}/{latest_deploy_version}/near',
            os.path.expanduser(f'~/.nearup/near/{net}/near'))
        download_near_s3(
            f'nearcore/{uname}/{net_to_branch(net)}/{latest_deploy_version}/keypair-generator',
            os.path.expanduser(f'~/.nearup/near/{net}/keypair-generator'))
        download_near_s3(
            f'nearcore/{uname}/{net_to_branch(net)}/{latest_deploy_version}/genesis-csv-to-json',
            os.path.expanduser(f'~/.nearup/near/{net}/genesis-csv-to-json'))
        subprocess.check_output(
            ['chmod', '+x',
             os.path.expanduser(f'~/.nearup/near/{net}/near')])
        subprocess.check_output([
            'chmod', '+x',
            os.path.expanduser(f'~/.nearup/near/{net}/keypair-generator')
        ])
        subprocess.check_output([
            'chmod', '+x',
            os.path.expanduser(f'~/.nearup/near/{net}/genesis-csv-to-json')
        ])
        with open(os.path.expanduser(f'~/.nearup/near/{net}/version'),
                  'w') as f:
            f.write(latest_deploy_version)
예제 #4
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def check_binary_version(binary_path, chain_id):
    latest_deploy_version = latest_deployed_version(chain_id)
    version = subprocess.check_output(
        [f'{binary_path}/near', '--version'],
        universal_newlines=True).split('(build ')[1].split(')')[0]
    if not latest_deploy_version.startswith(version):
        print(
            f'Warning: current deployed version on {chain_id} is {latest_deploy_version}, but local binary is {version}. It might not work'
        )
예제 #5
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def check_and_update_genesis(chain_id, home_dir):
    if genesis_changed(chain_id, home_dir):
        print(f'Update genesis config and remove stale data for {chain_id}')
        os.remove(os.path.join(home_dir, 'genesis.json'))
        download_genesis(chain_id, home_dir)
        if os.path.exists(os.path.join(home_dir, 'data')):
            shutil.rmtree(os.path.join(home_dir, 'data'))
        return True
    return False
예제 #6
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def binary_changed(net):
    latest_deploy_version = latest_deployed_version(net)
    if os.path.exists(os.path.expanduser(f'~/.nearup/near/{net}/version')):
        with open(os.path.expanduser(f'~/.nearup/near/{net}/version')) as f:
            version = f.read().strip()
            if version == latest_deploy_version:
                print('Downloaded binary version is up to date')
                return False
    return latest_deploy_version
예제 #7
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def print_staking_key(home_dir):
    key_path = os.path.join(home_dir, 'validator_key.json')
    if not os.path.exists(key_path):
        return

    key_file = json.loads(open(key_path).read())
    if not key_file['account_id']:
        print("Node is not staking. Re-run init to specify staking account.")
        return
    print("Stake for user '%s' with '%s'" %
          (key_file['account_id'], key_file['public_key']))
예제 #8
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def genesis_changed(chain_id, home_dir):
    genesis_md5sum = get_genesis_md5sum(chain_id)
    local_genesis_md5sum = hashlib.md5(
        open(os.path.join(os.path.join(home_dir, 'genesis.json')),
             'rb').read()).hexdigest()
    if genesis_md5sum == local_genesis_md5sum:
        print(f'Our genesis version is up to date')
        return False
    else:
        print(
            f'Remote genesis protocol version md5 {genesis_md5sum}, ours is {local_genesis_md5sum}'
        )
        return True
예제 #9
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def docker_changed(net):
    image = net_to_docker_image(net)
    print(f'Docker image: {image}')
    local_version = subprocess.check_output(
        ['docker', 'image', 'ls', '-q', '--filter', f'reference={image}'],
        universal_newlines=True).strip()
    if local_version:
        print(f'Local docker version: {local_version}')
        repo, *tag = image.split(':')
        if tag:
            tag = tag[0]
        else:
            tag = 'latest'
        auth_token = json.loads(
            download(
                f"https://auth.docker.io/token?service=registry.docker.io&scope=repository:{repo}:pull"
            ))['token']
        image_info = json.loads(
            download(
                f"https://index.docker.io/v2/{repo}/manifests/{tag}",
                headers=[
                    f"Authorization: Bearer {auth_token}",
                    "Accept: application/vnd.docker.distribution.manifest.v2+json"
                ]))
        remote_version = image_info["config"]["digest"].split(':')[1]
        print(f'Remote version: {remote_version}')
        if remote_version.startswith(local_version):
            print('Local docker image is up to date')
            return False
    return True
예제 #10
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def create_genesis(home, binary_path, nodocker, image, chain_id,
                   tracked_shards):
    if os.path.exists(os.path.join(home, 'genesis.json')):
        print("Genesis already exists")
        return
    print("Creating genesis...")
    if not os.path.exists(os.path.join(home, 'accounts.csv')):
        raise Exception(
            "Failed to generate genesis: accounts.csv does not exist")
    if nodocker:
        cmd = [f'{binary_path}/genesis-csv-to-json']
        cmd.extend(['--home', home])
        cmd.extend(['--chain-id', chain_id])
        if len(tracked_shards) > 0:
            cmd.extend(['--tracked-shards', tracked_shards])
        try:
            subprocess.call(cmd)
        except KeyboardInterrupt:
            print("\nStopping NEARCore.")
    else:
        subprocess.check_output(['mkdir', '-p', home])
        subprocess.check_output([
            'docker', 'run', '-u', USER, '-v',
            '%s:/srv/genesis-csv-to-json' % home, image, 'genesis-csv-to-json',
            '--home=/srv/genesis-csv-to-json',
            '--chain-id=%s' % chain_id,
            '--tracked-shards=%s' % tracked_shards
        ])
    print("Genesis created")
예제 #11
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def start_stakewars(home, binary_path, nodocker, image, verbose,
                    tracked_shards):
    create_genesis(home, binary_path, nodocker, image, 'stakewars',
                   tracked_shards)
    if nodocker:
        run_nodocker(home,
                     binary_path,
                     boot_nodes='',
                     verbose=verbose,
                     chain_id='stakewars')
    else:
        run_docker(image, home, boot_nodes='', verbose=verbose)
        print(
            "Node is running! \nTo check logs call: docker logs --follow nearcore"
        )
예제 #12
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def check_exist_neard():
    if os.path.exists(NODE_PID):
        print("There is already binary nodes running. Stop it using:")
        print("nearup stop")
        print(f"If this is a mistake, remove {NODE_PID}")
        exit(1)
    if shutil.which('docker') is not None:
        p = subprocess.Popen(['docker', 'ps', '-q', '-f', 'name=nearcore'],
                             universal_newlines=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        out, _ = p.communicate()
        if out.strip():
            print("There is already docker node running. Stop it using:")
            print("nearup stop")
            exit(1)
예제 #13
0
def stop_native():
    if os.path.exists(NODE_PID):
        with open(NODE_PID) as f:
            for line in f.readlines():
                pid, proc_name, _ = map(str.strip, line.strip(' \n').split("|"))
                pid = int(pid)
                if proc_name in proc_name_from_pid(pid):
                    print(f"Stopping process {proc_name} with pid", pid)
                    kill(pid, SIGTERM)
                    # Ensure the pid is killed, not just SIGTERM signal sent
                    while True:
                        try:
                            os.kill(pid, 0)
                        except OSError:
                            break

        unlink(NODE_PID)
예제 #14
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def stop_watcher():
    try:
        with open(os.path.expanduser(f'~/.nearup/watcher.pid')) as f:
            pid = int(f.read())
        kill(pid, SIGTERM)
        print(f'Stopping near watcher with pid {pid}')
        os.remove(os.path.expanduser(f'~/.nearup/watcher.pid'))
    except OSError:
        pass
    except FileNotFoundError:
        pass
    else:
        while True:
            try:
                os.kill(pid, 0)
            except OSError:
                break
예제 #15
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def run_docker_testnet(image,
                       home,
                       *,
                       shards=None,
                       validators=None,
                       non_validators=None):
    subprocess.check_output(['mkdir', '-p', home])
    home = os.path.abspath(home)
    command = [
        'docker', 'run', '-u', USER, '--rm', '-v',
        '%s:/srv/near' % home, image, 'near', '--home', '/srv/near', 'testnet'
    ]
    if shards:
        command.extend(['--shards', str(shards)])
    if validators:
        command.extend(['--v', str(validators)])
    if non_validators:
        command.extend(['--n', str(non_validators)])
    try:
        subprocess.check_output(command)
    except subprocess.CalledProcessError as e:
        print('Failed to run docker near. Error:', file=sys.stderr)
        print(e.stderr, file=sys.stderr)
        exit(1)
    except FileNotFoundError as exc:
        print(
            "Failed to run docker near: docker is not installed or not in PATH",
            file=sys.stderr)
        exit(1)
예제 #16
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def run_nodocker(home_dir,
                 binary_path,
                 boot_nodes,
                 verbose,
                 chain_id,
                 watch=False):
    """Runs NEAR core outside of docker."""
    print("Starting NEAR client...")
    os.environ['RUST_BACKTRACE'] = '1'
    pid_fd = open(NODE_PID, 'w')
    # convert verbose = True to --verbose '' command line argument
    if verbose:
        verbose = ''
    else:
        verbose = None
    LOGS_FOLDER = os.path.expanduser('~/.nearup/logs')
    subprocess.check_output(['mkdir', '-p', LOGS_FOLDER])
    proc = run_binary(os.path.join(binary_path, 'near'),
                      home_dir,
                      'run',
                      verbose=verbose,
                      boot_nodes=boot_nodes,
                      output=os.path.join(LOGS_FOLDER, chain_id),
                      watch=watch)
    proc_name = proc_name_from_pid(proc.pid)
    print(proc.pid, "|", proc_name, "|", chain_id, file=pid_fd)
    pid_fd.close()
    print(
        "Node is running! \nTo check logs call: `nearup logs` or `nearup logs --follow`"
    )
예제 #17
0
    def __init__(self):
        parser = argparse.ArgumentParser(description='Nearup',
                                         usage='''nearup <command> [<args>]

Commands are:
    mainnet    (Coming soon) Run a mainnet node
    testnet    Run a testnet node
    betanet    Run a betanet node
    localnet   Run a network with several nodes locally
    stop       Stop the currently running node
    logs       Show logs of currently running non docker node

Run nearup <command> --help to see help for specific command
''')
        parser.add_argument('command', help='Subcommand to run')
        args = parser.parse_args(sys.argv[1:2])
        if not hasattr(self, args.command):
            print('Unrecognized command', file=sys.stderr)
            parser.print_help(sys.stderr)
            exit(2)
        self.command = args.command
        getattr(self, args.command)()
예제 #18
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def generate_node_key(home, binary_path, nodocker, image):
    print("Generating node key...")
    if nodocker:
        cmd = [f'{binary_path}/keypair-generator']
        cmd.extend(['--home', home])
        cmd.extend(['--generate-config'])
        cmd.extend(['node-key'])
        try:
            subprocess.call(cmd)
        except KeyboardInterrupt:
            print("\nStopping NEARCore.")
    else:
        subprocess.check_output(['mkdir', '-p', home])
        subprocess.check_output([
            'docker', 'run', '-u', USER, '-v',
            '%s:/srv/keypair-generator' % home, image, 'keypair-generator',
            '--home=/srv/keypair-generator', '--generate-config', 'node-key'
        ])
    print("Node key generated")
예제 #19
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def run_docker(image,
               home_dir,
               boot_nodes,
               verbose,
               container_name='nearcore',
               host_network=False,
               watch=False):
    """Runs NEAR core inside the docker container"""
    print("Starting NEAR client docker...")
    docker_stop_if_exists(container_name)
    # Start nearcore container, mapping home folder and ports.
    envs = [
        '-e', 'RUST_BACKTRACE=1', '-e',
        'RUST_LOG=%s' % os.environ.get('RUST_LOG', '')
    ]
    home_dir = os.path.abspath(home_dir)
    rpc_port = get_port(home_dir, 'rpc')
    network_port = get_port(home_dir, 'network')
    cmd = ['near', '--home', '/srv/near']
    if verbose:
        cmd += ['--verbose', '']
    cmd.append('run')
    if boot_nodes:
        cmd.append('--boot-nodes=%s' % boot_nodes)
    if host_network:
        network_flags = ['--network', 'host']
    else:
        network_flags = ['-p', rpc_port, '-p', network_port]
    subprocess.check_output(['mkdir', '-p', home_dir])
    try:
        subprocess.check_output([
            'docker', 'run', '-u', USER, '-d', '-v',
            '%s:/srv/near' %
            home_dir, *network_flags, '-v', '/tmp:/tmp', '--ulimit', 'core=-1',
            '--name', container_name, '--restart', 'unless-stopped'
        ] + envs + [image] + cmd)
    except subprocess.CalledProcessError as e:
        print('Failed to run docker near. Error:', file=sys.stderr)
        print(e.stderr, file=sys.stderr)
        exit(1)
    if watch:
        run_watcher(watch, 'docker')
예제 #20
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def generate_signer_key(home, binary_path, nodocker, image, account_id):
    print("Generating signer keys...")
    if nodocker:
        cmd = [f'{binary_path}/keypair-generator']
        cmd.extend(['--home', home])
        cmd.extend(['--generate-config'])
        cmd.extend(['--account-id', account_id])
        cmd.extend(['signer-keys'])
        try:
            subprocess.call(cmd)
        except KeyboardInterrupt:
            print("\nStopping NEARCore.")
    else:
        subprocess.check_output(['mkdir', '-p', home])
        subprocess.check_output([
            'docker', 'run', '-u', USER, '-v',
            '%s:/srv/keypair-generator' % home, image, 'keypair-generator',
            '--home=/srv/keypair-generator', '--generate-config',
            '--account-id=%s' % account_id, 'signer-keys'
        ])
    print("Signer keys generated")
예제 #21
0
def nearup_restart(args):
    main_script = os.path.abspath(
        os.path.join(os.path.dirname(__file__), 'main.py'))
    subprocess.check_output(['python3', main_script, 'stop', '--keep-watcher'])
    subprocess.Popen(['python3', main_script, *args])
    print('done')
예제 #22
0

def nearup_restart(args):
    main_script = os.path.abspath(
        os.path.join(os.path.dirname(__file__), 'main.py'))
    subprocess.check_output(['python3', main_script, 'stop', '--keep-watcher'])
    subprocess.Popen(['python3', main_script, *args])
    print('done')


if __name__ == '__main__':
    net = sys.argv[1]
    home_dir = sys.argv[2]
    docker = sys.argv[3]
    args = sys.argv[4:]
    latest_deploy_at = get_latest_deploy_at(net)

    while True:
        time.sleep(60)
        try:
            new_latest_deploy_at = get_latest_deploy_at(net)
            if new_latest_deploy_at and new_latest_deploy_at != latest_deploy_at:
                print(
                    f'new deploy happens at {new_latest_deploy_at}, restart nearup'
                )
                nearup_restart(args)
                break
        except:
            traceback.print_exc()
            pass
예제 #23
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def check_and_setup(nodocker,
                    binary_path,
                    image,
                    home_dir,
                    init_flags,
                    no_gas_price=False):
    """Checks if there is already everything setup on this machine, otherwise sets up NEAR node."""
    chain_id = get_chain_id_from_flags(init_flags)
    if os.path.exists(os.path.join(home_dir)):
        missing = []
        for file in ['node_key.json', 'config.json', 'genesis.json']:
            if not os.path.exists(os.path.join(home_dir, file)):
                missing.append(file)
        if missing:
            print(
                f'Missing files {", ".join(missing)} in {home_dir}. Maybe last init was failed. either specify different --home or remove {home_dir} to start from scratch.',
                file=sys.stderr)
            exit(1)

        genesis_config = json.loads(
            open(os.path.join(os.path.join(home_dir, 'genesis.json'))).read())
        if genesis_config['chain_id'] != chain_id:
            print(
                f"Folder {home_dir} already has network configuration for {genesis_config['chain_id']}\n"
                f"You want to run {chain_id}, either specify different --home or remove {home_dir} to start from scratch.",
                file=sys.stderr)
            exit(1)

        if chain_id == 'devnet':
            if check_and_update_genesis(chain_id, home_dir):
                # For devnet, also update config because boot nodes changed
                print(f'Update devnet config for new boot nodes')
                os.remove(os.path.join(home_dir, 'config.json'))
                download_config('devnet', home_dir)
        elif chain_id in ['betanet', 'testnet']:
            check_and_update_genesis(chain_id, home_dir)
        else:
            print(f'Start {chain_id}')
            print("Using existing node configuration from %s for %s" %
                  (home_dir, genesis_config['chain_id']))
        return

    print("Setting up network configuration.")
    account_id = [x for x in init_flags if x.startswith('--account-id')]
    if not account_id:
        prompt = "Enter your account ID"
        if chain_id != '':
            prompt += " (leave empty if not going to be a validator): "
        else:
            prompt += ": "
        account_id = input(prompt)
        init_flags.append('--account-id=%s' % account_id)
    else:
        account_id = account_id[0].split('=')[-1]

    if nodocker:
        if chain_id in ['devnet', 'betanet', 'testnet']:
            nodocker_init_official(chain_id, binary_path, home_dir, account_id)
        else:
            nodocker_init(home_dir, binary_path, init_flags)
    else:
        if chain_id in ['devnet', 'betanet', 'testnet']:
            docker_init_official(chain_id, image, home_dir, account_id)
        else:
            docker_init(image, home_dir, init_flags)
    if chain_id not in ['devnet', 'betanet', 'testnet'] and no_gas_price:
        filename = os.path.join(home_dir, 'genesis.json')
        genesis_config = json.load(open(filename))
        genesis_config['gas_price'] = 0
        genesis_config['min_gas_price'] = 0
        json.dump(genesis_config, open(filename, 'w'))
    elif no_gas_price:
        print(
            f'no_gas_price is only for local development network, ignoring for {chain_id}'
        )
예제 #24
0
                            help='Follow logs')
        parser.add_argument(
            '-n',
            help='show given number of lines of logs (Default: 100)',
            default=100,
            type=int)
        self.args = parser.parse_args(sys.argv[2:])


if __name__ == '__main__':
    sys.argv[0] = 'nearup'
    nearup_arg_parser = NearupArgParser()
    command, args = nearup_arg_parser.command, nearup_arg_parser.args
    if command in ['devnet', 'betanet', 'testnet']:
        if args.local:
            print("Flag --local deprecated, please use --nodocker")
        nodocker = args.nodocker or args.local
        args.home = os.path.abspath(args.home)
        init_flags = [f'--chain-id={command}']
        if args.account_id:
            init_flags.append(f'--account-id={args.account_id}')
        setup_and_run(nodocker,
                      args.binary_path,
                      args.image,
                      args.home,
                      init_flags=init_flags,
                      boot_nodes=args.boot_nodes,
                      verbose=args.verbose,
                      args=sys.argv[1:])
    if command == 'mainnet':
        print(
예제 #25
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def stop_docker(containers):
    """Stops docker for Nearcore if they are running."""
    print('Stopping docker near')
    docker_stop_if_exists(containers)
예제 #26
0
파일: nodelib.py 프로젝트: JoowonYun/nearup
def setup_and_run(nodocker,
                  binary_path,
                  image,
                  home_dir,
                  init_flags,
                  boot_nodes,
                  verbose=False,
                  no_gas_price=False,
                  args=None):
    check_exist_neard()
    chain_id = get_chain_id_from_flags(init_flags)
    if nodocker:
        if binary_path == '':
            print(f'Using officially compiled binary')
            uname = os.uname()[0]
            if uname not in ['Linux', 'Darwin']:
                print(
                    'Sorry your Operating System does not have officially compiled binary now.\nPlease compile locally by `make debug` or `make release` in nearcore and set --binary-path'
                )
                exit(1)
            binary_path = os.path.expanduser(f'~/.nearup/near/{chain_id}')
            subprocess.check_output(['mkdir', '-p', binary_path])
            download_binary(chain_id, uname)
            watch = {"args": args, "net": chain_id, 'home': home_dir}
        else:
            print(f'Using local binary at {binary_path}')
            check_binary_version(binary_path, chain_id)
            watch = False
    else:
        if image == 'auto':
            image = net_to_docker_image(chain_id)
            watch = {"args": args, "net": chain_id, 'home': home_dir}
        else:
            watch = False
        try:
            print(f'Pull docker image {image}')
            subprocess.check_output(['docker', 'pull', image])
        except subprocess.CalledProcessError as exc:
            print("Failed to fetch docker containers: \n%s" % exc.stderr,
                  file=sys.stderr)
            exit(1)
        except FileNotFoundError as exc:
            print(
                "Failed to fetch docker containers, docker is not installed or not in PATH",
                file=sys.stderr)
            exit(1)

    check_and_setup(nodocker, binary_path, image, home_dir, init_flags,
                    no_gas_price)

    print_staking_key(home_dir)

    if nodocker:
        run_nodocker(home_dir,
                     binary_path,
                     boot_nodes,
                     verbose,
                     chain_id,
                     watch=watch)
    else:
        run_docker(image, home_dir, boot_nodes, verbose, watch=watch)
        print(
            "Node is running! \nTo check logs call: docker logs --follow nearcore"
        )