def run_docker_compose_up(keystore_password, composefile, trustednode): run_shell_command( ['docker-compose', '-f', composefile, 'up', '-d'], env={ "RADIXDLT_NETWORK_NODE": trustednode, "RADIXDLT_NODE_KEY_PASSWORD": keystore_password })
def setup_service_file(node_version_dir, node_dir="/etc/radixdlt/node", node_secrets_path="/etc/radixdlt/node/secrets"): command = f""" sudo cat > /etc/systemd/system/radixdlt-node.service << EOF [Unit] Description=Radix DLT Validator After=local-fs.target After=network-online.target After=nss-lookup.target After=time-sync.target After=systemd-journald-dev-log.socket Wants=network-online.target [Service] EnvironmentFile={node_secrets_path}/environment User=radixdlt LimitNOFILE=65536 LimitNPROC=65536 LimitMEMLOCK=infinity WorkingDirectory={node_dir} ExecStart={node_dir}/{node_version_dir}/bin/radixdlt SuccessExitStatus=143 TimeoutStopSec=10 Restart=on-failure [Install] WantedBy=multi-user.target """ run_shell_command(command, shell=True)
def set_environment_variables(keystore_password, node_secrets_dir): command = f""" cat > {node_secrets_dir}/environment << EOF JAVA_OPTS="--enable-preview -server -Xms8g -Xmx8g -XX:MaxDirectMemorySize=2048m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseCompressedOops -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts -Djavax.net.ssl.trustStoreType=jks -Djava.security.egd=file:/dev/urandom -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector" RADIX_NODE_KEYSTORE_PASSWORD={keystore_password} """ run_shell_command(command, shell=True)
def generatekey(keyfile_path, keyfile_name="node-keystore.ks", keygen_tag="1.0.0"): run_shell_command(f'mkdir -p {keyfile_path}', shell=True) keystore_password, keyfile_location = Base.generatekey( keyfile_path, keyfile_name, keygen_tag) return keystore_password, keyfile_location
def setup_user(): print("Checking if user radixdlt already exists") user_exists = run_shell_command("cat /etc/passwd | grep radixdlt", shell=True, fail_on_error=False) if user_exists.returncode != 0: run_shell_command('sudo useradd -m -s /bin/bash radixdlt ', shell=True) run_shell_command(['sudo', 'usermod', '-aG', 'docker', 'radixdlt'])
def backup_file(filepath, filename, backup_time): if os.path.isfile(f"{filepath}/{filename}"): # TODO AutoApprove backup_yes = input( f"{filename} file exists. Do you want to back up [Y/n]:") if Helpers.check_Yes(backup_yes): Path(f"{backup_time}").mkdir(parents=True, exist_ok=True) run_shell_command( f"cp {filepath}/{filename} {backup_time}/{filename}", shell=True)
def install_nginx(): nginx_installed = run_shell_command( "sudo service --status-all | grep nginx", shell=True, fail_on_error=False) if nginx_installed.returncode != 0: run_shell_command('sudo apt install -y nginx apache2-utils', shell=True) run_shell_command( 'sudo rm -rf /etc/nginx/{sites-available,sites-enabled}', shell=True)
def setup_compose_file(composefileurl, file_location, enable_transactions=False): compose_file_name = composefileurl.rsplit('/', 1)[-1] if os.path.isfile(compose_file_name): backup_file_name = f"{Helpers.get_current_date_time()}_{compose_file_name}" print( f"Docker compose file {compose_file_name} exists. Backing it up as {backup_file_name}" ) run_shell_command(f"cp {compose_file_name} {backup_file_name}", shell=True) print(f"Downloading new compose file from {composefileurl}") req = requests.Request('GET', f'{composefileurl}') prepared = req.prepare() resp = Helpers.send_request(prepared, print_response=False) if not resp.ok: print(f" Errored downloading file {composefileurl}. Exitting ... ") sys.exit() composefile_yaml = yaml.safe_load(resp.content) # TODO AutoApprove prompt_external_db = input( "Do you want to configure data directory for the ledger [Y/n]?:") if Helpers.check_Yes(prompt_external_db): composefile_yaml = Docker.merge_external_db_config( composefile_yaml) def represent_none(self, _): return self.represent_scalar('tag:yaml.org,2002:null', '') yaml.add_representer(type(None), represent_none) network_id = Base.get_network_id() genesis_json_location = Base.path_to_genesis_json(network_id) composefile_yaml = Docker.merge_network_info(composefile_yaml, network_id, genesis_json_location) composefile_yaml = Docker.merge_keyfile_path(composefile_yaml, file_location) composefile_yaml = Docker.merge_transactions_env_var( composefile_yaml, "true" if enable_transactions else "false") if os.getenv(IMAGE_OVERRIDE, "False") in ("true", "yes"): composefile_yaml = Docker.merge_image_overrides(composefile_yaml) with open(compose_file_name, 'w') as f: yaml.dump(composefile_yaml, f, default_flow_style=False, explicit_start=True, allow_unicode=True)
def setup(args): release = latest_release() if args.nodetype == "archivenode": Helpers.archivenode_deprecate_message() composefileurl = os.getenv( COMPOSE_FILE_OVERIDE, f"https://raw.githubusercontent.com/radixdlt/node-runner/{cli_version()}/node-runner-cli/release_ymls/radix-{args.nodetype}-compose.yml" ) print( f"Going to setup node type {args.nodetype} from location {composefileurl}.\n" ) # TODO autoapprove continue_setup = input("Do you want to continue [Y/n]?:") if not Helpers.check_Yes(continue_setup): print(" Quitting ....") sys.exit() keystore_password, file_location = Base.generatekey( keyfile_path=Helpers.get_keyfile_path(), keygen_tag=release) Docker.setup_compose_file(composefileurl, file_location, args.enabletransactions) trustednode_ip = Helpers.parse_trustednode(args.trustednode) compose_file_name = composefileurl.rsplit('/', 1)[-1] action = "update" if args.update else "start" print( f"About to {action} the node using docker-compose file {compose_file_name}, which is as below" ) run_shell_command(f"cat {compose_file_name}", shell=True) # TODO AutoApprove should_start = input(f"\nOkay to start the node [Y/n]?:") if Helpers.check_Yes(should_start): if action == "update": print( f"For update, bringing down the node using compose file {compose_file_name}" ) Docker.run_docker_compose_down(compose_file_name) Docker.run_docker_compose_up(keystore_password, compose_file_name, args.trustednode) else: print(f""" --------------------------------------------------------------- Bring up node by updating the file {compose_file_name} You can do it through cli using below command radixnode docker stop -f {compose_file_name} radixnode docker start -f {compose_file_name} -t {args.trustednode} ---------------------------------------------------------------- """)
def add_user_docker_group(): run_shell_command('sudo groupadd docker', shell=True, fail_on_error=False) is_in_docker_group = run_shell_command('groups | grep docker', shell=True, fail_on_error=False) if is_in_docker_group.returncode != 0: run_shell_command( f"sudo usermod -aG docker {os.environ.get('USER')}", shell=True) print( 'Exit ssh login and relogin back for user addition to group "docker" to take effect' )
def start_node_service(): run_shell_command('sudo chown radixdlt:radixdlt -R /etc/radixdlt', shell=True) run_shell_command('sudo systemctl start radixdlt-node.service', shell=True) run_shell_command('sudo systemctl enable radixdlt-node.service', shell=True) run_shell_command('sudo systemctl restart radixdlt-node.service', shell=True)
def setup_default_config(trustednode, hostip, node_dir, node_type, keyfile_name="node-keystore.ks", transactions_enable="false"): network_id = SystemD.get_network_id() genesis_json_location = Base.path_to_genesis_json(network_id) network_genesis_file_for_testnets = f"network.genesis_file={genesis_json_location}" if genesis_json_location else "" enable_client_api = "true" if node_type == "archivenode" else "false" data_folder = Base.get_data_dir() command = f""" cat > {node_dir}/default.config << EOF ntp=false ntp.pool=pool.ntp.org network.id={network_id} {network_genesis_file_for_testnets} node.key.path=/etc/radixdlt/node/secrets/{keyfile_name} network.p2p.listen_port=30001 network.p2p.broadcast_port=30000 network.p2p.seed_nodes={trustednode} network.host_ip={hostip} db.location={data_folder} api.port=3334 log.level=debug api.transactions.enable={"true" if transactions_enable else "false"} api.sign.enable=true api.bind.address=0.0.0.0 network.p2p.use_proxy_protocol=false """ run_shell_command(command, shell=True) if (os.getenv(APPEND_DEFAULT_CONFIG_OVERIDES)) is not None: print("Add overides") lines = [] while True: line = input() if line: lines.append(line) else: break for text in lines: run_shell_command(f"echo {text} >> {node_dir}/default.config", shell=True)
def setup_node_optimisation_config(version): check_ansible = run_shell_command(f"pip list | grep ansible", shell=True, fail_on_error=False) import subprocess user = subprocess.check_output('whoami', shell=True).strip() if check_ansible.returncode != 0: print( f"Ansible not found for the user {user.decode('utf-8')}. Installing ansible now" ) check_pip = run_shell_command("pip -V ", shell=True, fail_on_error=False) if check_pip.returncode != 0: print(f"Pip is not installed. Installing pip now") run_shell_command('sudo apt install python3-pip', shell=True) run_shell_command(f"pip install --user ansible==2.10.0", shell=True) print(""" ---------------------------------------------------------------------------------------- Ansible installed successfully. You need exit shell and login back""" ) sys.exit() ansible_dir = f'https://raw.githubusercontent.com/radixdlt/node-runner/{version}/node-runner-cli' print(f"Downloading artifacts from {ansible_dir}\n") Base.download_ansible_file(ansible_dir, 'ansible/project/provision.yml') ask_setup_limits = input \ ("Do you want to setup ulimits [Y/n]?:") setup_limits = "true" if Helpers.check_Yes( ask_setup_limits) else "false" run_shell_command( f"ansible-playbook ansible/project/provision.yml -e setup_limits={setup_limits}", shell=True) ask_setup_swap = input \ ("Do you want to setup swap space [Y/n]?:") if Helpers.check_Yes(ask_setup_swap): setup_swap = "true" ask_swap_size = input \ ("Enter swap size in GB. Example - 1G or 3G or 8G ?:") run_shell_command( f"ansible-playbook ansible/project/provision.yml -e setup_swap={setup_swap} -e swap_size={ask_swap_size}", shell=True) else: setup_swap = "false"
def download_binaries(binarylocationUrl, node_dir, node_version): run_shell_command([ 'wget', '--no-check-certificate', '-O', 'radixdlt-dist.zip', binarylocationUrl ]) run_shell_command('unzip radixdlt-dist.zip', shell=True) run_shell_command(f'mkdir -p {node_dir}/{node_version}', shell=True) if os.listdir(f'{node_dir}/{node_version}'): print(f"Directory {node_dir}/{node_version} is not empty") okay = input("Should the directory be removed [Y/n]?:") if Helpers.check_Yes(okay): run_shell_command(f"rm -rf {node_dir}/{node_version}/*", shell=True) unzipped_folder_name = os.getenv(UNZIPPED_NODE_DIST_FOLDER, f"radixdlt-{node_version}") run_shell_command( f'mv {unzipped_folder_name}/* {node_dir}/{node_version}', shell=True)
def setup_nginx_config(nginx_config_location_Url, node_type, nginx_etc_dir, backup_time): SystemD.install_nginx() if node_type == "archivenode": conf_file = 'nginx-archive.conf' elif node_type == "fullnode": conf_file = 'nginx-fullnode.conf' else: print( f"Node type - {node_type} specificed should be either archivenode or fullnode" ) sys.exit() backup_yes = input( "Do you want to backup existing nginx config [Y/n]?:") if Helpers.check_Yes(backup_yes): Path(f"{backup_time}/nginx-config").mkdir(parents=True, exist_ok=True) run_shell_command( f"sudo cp -r {nginx_etc_dir} {backup_time}/nginx-config", shell=True) # TODO AutoApprove continue_nginx = input( "Do you want to continue with nginx setup [Y/n]?:") if Helpers.check_Yes(continue_nginx): run_shell_command([ 'wget', '--no-check-certificate', '-O', 'radixdlt-nginx.zip', nginx_config_location_Url ]) run_shell_command( f'sudo unzip radixdlt-nginx.zip -d {nginx_etc_dir}', shell=True) run_shell_command( f'sudo mv {nginx_etc_dir}/{conf_file} /etc/nginx/nginx.conf', shell=True) run_shell_command(f'sudo mkdir -p /var/cache/nginx/radixdlt-hot', shell=True) return True else: return False
def checkUser(): print("\nChecking the user is radixdlt") result = run_shell_command(f'whoami | grep radixdlt', shell=True, fail_on_error=False) if result.returncode != 0: print( " You are not logged as radixdlt user. Logout and login as radixdlt user" ) sys.exit() else: print("User on the terminal is radixdlt")
def setup_nginx_Password(usertype, username): print('-----------------------------') print( f'Setting up nginx user of type {usertype} with username {username}' ) nginx_password = getpass.getpass(f"Enter your nginx the password: "******""" Setup NGINX_{usertype.upper()}_PASSWORD environment variable using below command . Replace the string 'nginx_password_of_your_choice' with your password echo 'export NGINX_{usertype.upper()}_PASSWORD="******"' >> ~/.bashrc """) if username not in ["admin", "metrics", "superadmin"]: print(f""" echo 'export NGINX_{usertype.upper()}_USERNAME="******"' >> ~/.bashrc """) return nginx_password
def generatekey(keyfile_path, keyfile_name="node-keystore.ks", keygen_tag="1.0.0"): print('-----------------------------') if os.path.isfile(f'{keyfile_path}/{keyfile_name}'): # TODO AutoApprove print(f"Node key file already exist at location {keyfile_path}") keystore_password = getpass.getpass( f"Enter the password of the existing keystore file '{keyfile_name}':" ) else: # TODO AutoApprove ask_keystore_exists = input \ (f"Do you have keystore file named '{keyfile_name}' already from previous node Y/n?:") if Helpers.check_Yes(ask_keystore_exists): print( f"Copy the keystore file '{keyfile_name}' to the location {keyfile_path} and then rerun the command" ) sys.exit() else: print(f""" Generating new keystore file. Don't forget to backup the key from location {keyfile_path}/{keyfile_name} """) keystore_password = getpass.getpass( f"Enter the password of the new file '{keyfile_name}':") # TODO keygen image needs to be updated run_shell_command([ 'docker', 'run', '--rm', '-v', keyfile_path + ':/keygen/key', f'radixdlt/keygen:{keygen_tag}', f'--keystore=/keygen/key/{keyfile_name}', '--password='******'sudo', 'chmod', '644', f'{keyfile_path}/{keyfile_name}']) return keystore_password, f'{keyfile_path}/{keyfile_name}'
def create_ssl_certs(secrets_dir): SystemD.make_nginx_secrets_directory() if os.path.isfile(f'{secrets_dir}/server.key') and os.path.isfile( f'{secrets_dir}/server.pem'): print( f"Files {secrets_dir}/server.key and os.path.isfile(f'{secrets_dir}/server.pem already exists" ) answer = input("Do you want to regenerate y/n :") if Helpers.check_Yes(answer): run_shell_command(f""" sudo openssl req -nodes -new -x509 -nodes -subj '/CN=localhost' \ -keyout "{secrets_dir}/server.key" \ -out "{secrets_dir}/server.pem" """, shell=True) else: run_shell_command(f""" sudo openssl req -nodes -new -x509 -nodes -subj '/CN=localhost' \ -keyout "{secrets_dir}/server.key" \ -out "{secrets_dir}/server.pem" """, shell=True) if os.path.isfile(f'{secrets_dir}/dhparam.pem'): print(f"File {secrets_dir}/dhparam.pem already exists") answer = input("Do you want to regenerate y/n :") if Helpers.check_Yes(answer): run_shell_command( f"sudo openssl dhparam -out {secrets_dir}/dhparam.pem 4096", shell=True) else: print("Generating a dhparam.pem file") run_shell_command( f"sudo openssl dhparam -out {secrets_dir}/dhparam.pem 4096", shell=True)
def setup_nginx_password(secrets_dir, usertype, username): run_shell_command(f'sudo mkdir -p {secrets_dir}', shell=True) print('-----------------------------') print(f'Setting up nginx password for user of type {usertype}') run_shell_command(f'sudo touch {secrets_dir}/htpasswd.{usertype}', fail_on_error=True, shell=True) run_shell_command( f'sudo htpasswd -c {secrets_dir}/htpasswd.{usertype} {username}', shell=True) print( f"""Setup NGINX_{usertype.upper()}_PASSWORD environment variable using below command . Replace the string 'nginx_password_of_your_choice' with your password $ echo 'export NGINX_{usertype.upper()}_PASSWORD="******"' >> ~/.bashrc $ source ~/.bashrc """) if username not in ["admin", "metrics", "superadmin"]: print(f""" echo 'export NGINX_{usertype.upper()}_USERNAME="******"' >> ~/.bashrc """)
def create_initial_service_file(): run_shell_command( "sudo touch /etc/systemd/system/radixdlt-node.service", shell=True) run_shell_command( "sudo chown radixdlt:radixdlt /etc/systemd/system/radixdlt-node.service", shell=True)
def fetch_universe_json(trustenode, extraction_path="."): run_shell_command( f'sudo wget --no-check-certificate -O {extraction_path}/universe.json https://{trustenode}/universe.json', shell=True)
def get_data_dir(): # TODO AutoApprove data_dir_path = input("Enter the absolute path to data DB folder:") run_shell_command(f'sudo mkdir -p {data_dir_path}', shell=True) return data_dir_path
def install_dependecies(): run_shell_command('sudo apt update', shell=True) run_shell_command( 'sudo apt install -y docker.io wget unzip docker-compose rng-tools', shell=True) run_shell_command('sudo rngd -r /dev/random', shell=True)
def restart_nginx_service(): run_shell_command('sudo systemctl daemon-reload', shell=True) run_shell_command('sudo systemctl restart nginx', shell=True)
def stop_nginx_service(): run_shell_command('sudo systemctl stop nginx', shell=True) run_shell_command('sudo systemctl disable nginx', shell=True)
def restart_node_service(): run_shell_command('sudo systemctl daemon-reload', shell=True) run_shell_command('sudo systemctl restart radixdlt-node.service', shell=True)
def make_data_directory(): run_shell_command('sudo mkdir -p /data', shell=True) run_shell_command('sudo chown radixdlt:radixdlt -R /data', shell=True)
def make_etc_directory(): run_shell_command('sudo mkdir -p /etc/radixdlt/', shell=True) run_shell_command('sudo chown radixdlt:radixdlt -R /etc/radixdlt', shell=True)
def stop_node_service(): run_shell_command('sudo systemctl stop radixdlt-node.service', shell=True) run_shell_command('sudo systemctl disable radixdlt-node.service', shell=True)