2019-06-15 23:02:44 +00:00
|
|
|
from config import *
|
2019-11-04 04:50:47 +00:00
|
|
|
from threading import Timer
|
2019-11-14 02:32:37 +00:00
|
|
|
import time
|
2019-06-15 23:02:44 +00:00
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
|
2019-08-27 01:36:15 +00:00
|
|
|
# Globals
|
|
|
|
local_ip = "unknown"
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
|
|
|
|
#==================================
|
|
|
|
# Manage Device
|
|
|
|
#==================================
|
|
|
|
def reboot_device():
|
|
|
|
os.system("sync")
|
|
|
|
os.system("/usr/bin/mynode_stop_critical_services.sh")
|
|
|
|
os.system("reboot")
|
|
|
|
|
|
|
|
def shutdown_device():
|
|
|
|
os.system("sync")
|
|
|
|
os.system("/usr/bin/mynode_stop_critical_services.sh")
|
|
|
|
os.system("shutdown -h now")
|
|
|
|
|
|
|
|
def factory_reset():
|
|
|
|
# Reset subsystems that have local data
|
|
|
|
delete_quicksync_data()
|
|
|
|
|
|
|
|
# Delete LND data
|
|
|
|
delete_lnd_data()
|
|
|
|
|
|
|
|
# Delete Tor data
|
|
|
|
reset_tor()
|
|
|
|
|
|
|
|
# Disable services
|
|
|
|
os.system("systemctl disable electrs --no-pager")
|
|
|
|
os.system("systemctl disable lndhub --no-pager")
|
|
|
|
os.system("systemctl disable btc_rpc_explorer --no-pager")
|
|
|
|
os.system("systemctl disable vpn --no-pager")
|
|
|
|
|
|
|
|
# Trigger drive to be reformatted on reboot
|
|
|
|
os.system("rm -f /mnt/hdd/.mynode")
|
|
|
|
|
|
|
|
# Reset password
|
|
|
|
os.system("/usr/bin/mynode_chpasswd.sh bolt")
|
|
|
|
|
|
|
|
# Reboot
|
|
|
|
reboot_device()
|
|
|
|
|
|
|
|
#==================================
|
|
|
|
# Manage Versions and Upgrades
|
|
|
|
#==================================
|
2019-06-15 23:02:44 +00:00
|
|
|
def get_current_version():
|
|
|
|
current_version = "0.0"
|
|
|
|
try:
|
|
|
|
with open("/usr/share/mynode/version", "r") as f:
|
|
|
|
current_version = f.read().strip()
|
|
|
|
except:
|
|
|
|
current_version = "error"
|
|
|
|
return current_version
|
|
|
|
|
|
|
|
|
|
|
|
def update_latest_version():
|
2019-06-30 16:50:05 +00:00
|
|
|
os.system("wget "+LATEST_VERSION_URL+" -O /usr/share/mynode/latest_version")
|
2019-06-15 23:02:44 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def get_latest_version():
|
|
|
|
latest_version = "0.0"
|
|
|
|
try:
|
|
|
|
with open("/usr/share/mynode/latest_version", "r") as f:
|
|
|
|
latest_version = f.read().strip()
|
2019-11-02 04:04:37 +00:00
|
|
|
if latest_version == "":
|
|
|
|
latest_version = get_current_version()
|
2019-06-15 23:02:44 +00:00
|
|
|
except:
|
|
|
|
latest_version = get_current_version()
|
|
|
|
return latest_version
|
|
|
|
|
2020-01-26 03:39:55 +00:00
|
|
|
def reinstall_app(app):
|
|
|
|
# Upgrade
|
|
|
|
os.system("mkdir -p /home/admin/upgrade_logs")
|
|
|
|
cmd = "/usr/bin/mynode_reinstall_app.sh {} 2>&1".format(app)
|
|
|
|
subprocess.call(cmd, shell=True)
|
|
|
|
|
|
|
|
# Sync
|
|
|
|
os.system("sync")
|
|
|
|
time.sleep(1)
|
|
|
|
|
|
|
|
# Reboot
|
|
|
|
reboot_device()
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def upgrade_device():
|
|
|
|
# Upgrade
|
|
|
|
os.system("mkdir -p /home/admin/upgrade_logs")
|
|
|
|
cmd = "/usr/bin/mynode_upgrade.sh > /home/admin/upgrade_logs/upgrade_log_from_{}_upgrade.txt 2>&1".format(get_current_version())
|
|
|
|
subprocess.call(cmd, shell=True)
|
|
|
|
|
|
|
|
# Sync
|
|
|
|
os.system("sync")
|
|
|
|
time.sleep(1)
|
2019-06-15 23:02:44 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
# Reboot
|
|
|
|
reboot_device()
|
2020-01-10 05:41:12 +00:00
|
|
|
|
2019-11-16 20:46:00 +00:00
|
|
|
def did_upgrade_fail():
|
|
|
|
return os.path.isfile("/mnt/hdd/mynode/settings/upgrade_error")
|
|
|
|
|
2020-01-24 18:07:03 +00:00
|
|
|
def get_recent_upgrade_logs():
|
|
|
|
logs=""
|
|
|
|
current_version = get_current_version()
|
|
|
|
for i in range(1,6):
|
|
|
|
filename = "/home/admin/upgrade_logs/upgrade_log_{}_post_{}.txt".format(current_version, i)
|
|
|
|
try:
|
|
|
|
with open(filename, "r") as f:
|
|
|
|
logs = logs + "===========================================================\n"
|
|
|
|
logs = logs + "=== Upgrade Attempt #{}\n".format(i)
|
|
|
|
logs = logs + "===========================================================\n\n\n"
|
|
|
|
logs = logs + f.read().decode("utf8")
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return logs
|
|
|
|
|
2019-11-16 20:46:00 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Device Info
|
|
|
|
#==================================
|
2019-06-29 15:53:49 +00:00
|
|
|
def get_system_uptime():
|
|
|
|
uptime = subprocess.check_output('awk \'{print int($1/86400)" days "int($1%86400/3600)" hour(s) "int(($1%3600)/60)" minute(s) "int($1%60)" seconds(s)"}\' /proc/uptime', shell=True)
|
|
|
|
uptime = uptime.strip()
|
|
|
|
return uptime
|
|
|
|
|
2020-02-05 02:12:52 +00:00
|
|
|
def get_system_date():
|
|
|
|
date = subprocess.check_output('date', shell=True)
|
|
|
|
date = date.strip()
|
|
|
|
return date
|
|
|
|
|
2019-06-15 23:02:44 +00:00
|
|
|
def get_device_serial():
|
|
|
|
serial = subprocess.check_output("cat /proc/cpuinfo | grep Serial | cut -d ' ' -f 2", shell=True)
|
|
|
|
serial = serial.strip()
|
2019-10-08 03:11:54 +00:00
|
|
|
if serial == "":
|
|
|
|
# For VMs, use the UUID
|
|
|
|
serial = subprocess.check_output("sudo dmidecode | grep UUID | cut -d ' ' -f 2", shell=True)
|
|
|
|
serial = serial.strip()
|
2019-06-15 23:02:44 +00:00
|
|
|
return serial
|
|
|
|
|
2019-07-16 03:30:08 +00:00
|
|
|
def get_device_type():
|
2019-10-30 02:22:11 +00:00
|
|
|
device = subprocess.check_output("mynode-get-device-type", shell=True)
|
|
|
|
return device
|
2019-07-16 03:30:08 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def get_local_ip():
|
|
|
|
local_ip = "unknown"
|
|
|
|
try:
|
|
|
|
local_ip = subprocess.check_output('/usr/bin/get_local_ip.py', shell=True).strip()
|
|
|
|
except:
|
|
|
|
local_ip = "error"
|
|
|
|
|
|
|
|
return local_ip
|
|
|
|
|
|
|
|
def get_device_changelog():
|
|
|
|
changelog = ""
|
|
|
|
try:
|
|
|
|
changelog = subprocess.check_output(["cat", "/usr/share/mynode/changelog"])
|
|
|
|
except:
|
|
|
|
changelog = "ERROR"
|
|
|
|
return changelog
|
|
|
|
|
|
|
|
def has_changed_password():
|
|
|
|
return os.path.isfile("/home/bitcoin/.mynode/.hashedpw")
|
|
|
|
|
2019-07-16 03:30:08 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Service Status, Enabled, Logs, etc...
|
|
|
|
#==================================
|
|
|
|
def is_service_enabled(service_name):
|
|
|
|
cmd = "systemctl is-enabled {}".format(service_name)
|
|
|
|
try:
|
|
|
|
subprocess.check_call(cmd, shell=True)
|
|
|
|
return True
|
|
|
|
except:
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get_service_status_code(service_name):
|
|
|
|
code = os.system("systemctl status {} --no-pager".format(service_name))
|
|
|
|
return code
|
|
|
|
|
|
|
|
def get_service_status_basic_text(service_name):
|
|
|
|
if not is_service_enabled(service_name):
|
|
|
|
return "Disabled"
|
|
|
|
|
|
|
|
code = os.system("systemctl status {} --no-pager".format(service_name))
|
|
|
|
if code == 0:
|
|
|
|
return "Running"
|
|
|
|
return "Error"
|
|
|
|
|
|
|
|
def get_service_status_color(service_name):
|
|
|
|
if not is_service_enabled(service_name):
|
|
|
|
return "gray"
|
|
|
|
|
|
|
|
code = os.system("systemctl status {} --no-pager".format(service_name))
|
|
|
|
if code == 0:
|
|
|
|
return "green"
|
|
|
|
return "red"
|
|
|
|
|
|
|
|
def get_journalctl_log(service_name):
|
|
|
|
try:
|
2020-02-23 21:55:05 +00:00
|
|
|
log = subprocess.check_output("journalctl -r --unit={} --no-pager | head -n 200".format(service_name), shell=True).decode("utf8")
|
2020-01-11 02:04:31 +00:00
|
|
|
except:
|
|
|
|
log = "ERROR"
|
|
|
|
return log
|
|
|
|
|
|
|
|
|
|
|
|
#==================================
|
|
|
|
# Uploader Functions
|
|
|
|
#==================================
|
2019-07-25 02:51:12 +00:00
|
|
|
def is_uploader():
|
2019-08-01 00:47:04 +00:00
|
|
|
return os.path.isfile("/home/bitcoin/.mynode/uploader") or \
|
|
|
|
os.path.isfile("/mnt/hdd/mynode/settings/uploader")
|
|
|
|
def set_uploader():
|
|
|
|
os.system("touch /home/bitcoin/.mynode/uploader")
|
|
|
|
os.system("touch /mnt/hdd/mynode/settings/uploader")
|
|
|
|
def unset_uploader():
|
|
|
|
os.system("rm -rf /home/bitcoin/.mynode/uploader")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/uploader")
|
2019-07-25 02:51:12 +00:00
|
|
|
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# QuickSync Functions
|
|
|
|
#==================================
|
2019-08-01 02:46:22 +00:00
|
|
|
def is_quicksync_enabled():
|
2019-10-24 04:18:46 +00:00
|
|
|
return not os.path.isfile("/mnt/hdd/mynode/settings/quicksync_disabled")
|
2019-08-01 02:46:22 +00:00
|
|
|
def disable_quicksync():
|
|
|
|
os.system("touch /mnt/hdd/mynode/settings/quicksync_disabled")
|
|
|
|
def enable_quicksync():
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/quicksync_disabled")
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def settings_disable_quicksync():
|
|
|
|
stop_bitcoind()
|
|
|
|
stop_quicksync()
|
|
|
|
disable_quicksync()
|
|
|
|
delete_quicksync_data()
|
|
|
|
reboot_device()
|
|
|
|
|
|
|
|
def settings_enable_quicksync():
|
|
|
|
stop_bitcoind()
|
|
|
|
stop_quicksync()
|
|
|
|
enable_quicksync()
|
|
|
|
delete_quicksync_data()
|
|
|
|
reboot_device()
|
|
|
|
|
|
|
|
def delete_quicksync_data():
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/quicksync")
|
|
|
|
os.system("rm -rf /home/bitcoin/.config/transmission") # Old dir
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/.config/transmission")
|
|
|
|
|
|
|
|
def stop_quicksync():
|
|
|
|
os.system("systemctl stop quicksync")
|
2019-08-01 02:46:22 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def restart_quicksync():
|
|
|
|
os.system('echo "quicksync_reset" > /mnt/hdd/mynode/.mynode_status')
|
|
|
|
stop_bitcoind()
|
|
|
|
stop_quicksync()
|
|
|
|
delete_bitcoin_data()
|
|
|
|
delete_quicksync_data()
|
|
|
|
enable_quicksync()
|
|
|
|
reboot_device()
|
|
|
|
|
|
|
|
|
|
|
|
#==================================
|
|
|
|
# Product Key Functions
|
|
|
|
#==================================
|
2019-06-15 23:02:44 +00:00
|
|
|
def set_skipped_product_key():
|
|
|
|
os.system("touch /home/bitcoin/.mynode/.product_key_skipped")
|
2019-07-06 01:45:42 +00:00
|
|
|
os.system("touch /mnt/hdd/mynode/settings/.product_key_skipped")
|
2019-06-15 23:02:44 +00:00
|
|
|
def unset_skipped_product_key():
|
|
|
|
os.system("rm -rf /home/bitcoin/.mynode/.product_key_skipped")
|
2019-07-06 01:45:42 +00:00
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/.product_key_skipped")
|
2019-06-15 23:02:44 +00:00
|
|
|
def skipped_product_key():
|
2019-08-01 00:47:04 +00:00
|
|
|
return os.path.isfile("/home/bitcoin/.mynode/.product_key_skipped") or \
|
|
|
|
os.path.isfile("/mnt/hdd/mynode/settings/.product_key_skipped")
|
2019-09-02 02:08:55 +00:00
|
|
|
def is_community_edition():
|
|
|
|
return skipped_product_key()
|
2019-06-15 23:02:44 +00:00
|
|
|
|
|
|
|
def delete_product_key():
|
|
|
|
os.system("rm -rf /home/bitcoin/.mynode/.product_key")
|
2019-07-06 01:45:42 +00:00
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/.product_key")
|
2019-06-15 23:02:44 +00:00
|
|
|
def has_product_key():
|
|
|
|
return os.path.isfile("/home/bitcoin/.mynode/.product_key")
|
|
|
|
def get_product_key():
|
|
|
|
product_key = "no_product_key"
|
|
|
|
if skipped_product_key():
|
|
|
|
return "community_edition"
|
|
|
|
|
|
|
|
if not has_product_key():
|
|
|
|
return "product_key_missing"
|
|
|
|
|
|
|
|
try:
|
|
|
|
with open("/home/bitcoin/.mynode/.product_key", "r") as f:
|
|
|
|
product_key = f.read().strip()
|
|
|
|
except:
|
|
|
|
product_key = "product_key_error"
|
|
|
|
return product_key
|
|
|
|
def is_valid_product_key():
|
|
|
|
return not os.path.isfile("/home/bitcoin/.mynode/.product_key_error")
|
|
|
|
def save_product_key(product_key):
|
|
|
|
pk = product_key.replace("-","")
|
|
|
|
os.system("echo '{}' > /home/bitcoin/.mynode/.product_key".format(pk))
|
2019-07-06 01:45:42 +00:00
|
|
|
os.system("echo '{}' > /mnt/hdd/mynode/settings/.product_key".format(pk))
|
2019-06-15 23:02:44 +00:00
|
|
|
def delete_product_key_error():
|
|
|
|
os.system("rm -rf /home/bitcoin/.mynode/.product_key_error")
|
2019-07-06 01:45:42 +00:00
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/.product_key_error")
|
2019-12-23 18:20:09 +00:00
|
|
|
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Drive Repair Functions
|
|
|
|
#==================================
|
2019-12-22 03:27:14 +00:00
|
|
|
def is_drive_being_repaired():
|
|
|
|
return os.path.isfile("/tmp/repairing_drive")
|
2019-12-12 01:34:34 +00:00
|
|
|
def has_fsck_error():
|
|
|
|
return os.path.isfile("/tmp/fsck_error")
|
|
|
|
def get_fsck_results():
|
|
|
|
try:
|
|
|
|
with open("/tmp/fsck_results", "r") as f:
|
|
|
|
return f.read()
|
|
|
|
except:
|
|
|
|
return "ERROR"
|
|
|
|
return "ERROR"
|
2019-08-27 01:36:15 +00:00
|
|
|
|
2019-12-23 18:20:09 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Docker Functions
|
|
|
|
#==================================
|
2019-12-23 18:20:09 +00:00
|
|
|
def is_installing_docker_images():
|
|
|
|
return os.path.isfile("/tmp/installing_docker_images")
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def get_docker_image_build_status():
|
|
|
|
status_code = get_service_status_code("docker_images")
|
2019-12-23 18:20:09 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
if status_code != 0:
|
|
|
|
return "Failed... Retrying Later"
|
2019-09-10 03:15:14 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
if is_installing_docker_images():
|
|
|
|
return "Installing..."
|
|
|
|
else:
|
|
|
|
return "Installation Complete"
|
2019-09-10 03:15:14 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
return "Unknown"
|
2019-10-20 03:20:03 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def get_docker_image_build_status_color():
|
|
|
|
status_code = get_service_status_code("docker_images")
|
|
|
|
if status_code != 0:
|
|
|
|
return "red"
|
|
|
|
return "green"
|
2019-10-26 16:32:06 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Bitcoin Functions
|
|
|
|
#==================================
|
2019-10-26 16:32:06 +00:00
|
|
|
def get_bitcoin_rpc_password():
|
|
|
|
try:
|
|
|
|
with open("/mnt/hdd/mynode/settings/.btcrpcpw", "r") as f:
|
|
|
|
return f.read()
|
|
|
|
except:
|
|
|
|
return "ERROR"
|
2019-11-04 04:50:47 +00:00
|
|
|
return "ERROR"
|
|
|
|
|
|
|
|
def stop_bitcoind():
|
|
|
|
os.system("systemctl stop bitcoind")
|
|
|
|
|
|
|
|
def reset_bitcoin_env_file():
|
|
|
|
os.system("echo 'BTCARGS=' > "+BITCOIN_ENV_FILE)
|
|
|
|
|
|
|
|
def delete_bitcoin_data():
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/bitcoin")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/quicksync/.quicksync_complete")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/.btcrpc_environment")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/.btcrpcpw")
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def reset_blockchain():
|
|
|
|
stop_bitcoind()
|
|
|
|
delete_bitcoin_data()
|
|
|
|
reboot_device()
|
2019-11-04 04:50:47 +00:00
|
|
|
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# LND Functions
|
|
|
|
#==================================
|
|
|
|
def stop_lnd():
|
|
|
|
os.system("systemctl stop lnd")
|
|
|
|
|
|
|
|
def restart_lnd():
|
|
|
|
os.system("systemctl restart lnd")
|
2019-11-04 04:50:47 +00:00
|
|
|
|
|
|
|
def delete_lnd_data():
|
|
|
|
#os.system("rm -f "+LND_WALLET_FILE)
|
|
|
|
os.system("rm -rf "+LND_DATA_FOLDER)
|
|
|
|
os.system("rm -rf /home/bitcoin/.lnd-admin/credentials.json")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/.lndpw")
|
|
|
|
os.system("rm -rf /home/admin/.lnd/")
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2020-02-06 01:15:32 +00:00
|
|
|
#==================================
|
|
|
|
# Electrum Server Functions
|
|
|
|
#==================================
|
|
|
|
def stop_electrs():
|
|
|
|
os.system("systemctl stop electrs")
|
|
|
|
|
|
|
|
def delete_electrs_data():
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/electrs")
|
|
|
|
|
|
|
|
def reset_electrs():
|
|
|
|
stop_electrs()
|
|
|
|
delete_electrs_data()
|
|
|
|
reboot_device()
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Tor Functions
|
|
|
|
#==================================
|
2019-11-04 04:50:47 +00:00
|
|
|
def reset_tor():
|
|
|
|
os.system("rm -rf /var/lib/tor/*")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/bitcoin/onion_private_key")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/lnd/v2_onion_private_key")
|
2020-01-29 01:59:46 +00:00
|
|
|
|
|
|
|
def is_btc_lnd_tor_enabled():
|
|
|
|
return os.path.isfile("/mnt/hdd/mynode/settings/.btc_lnd_tor_enabled")
|
|
|
|
|
|
|
|
def enable_btc_lnd_tor():
|
|
|
|
os.system("touch mnt/hdd/mynode/settings/.btc_lnd_tor_enabled")
|
|
|
|
os.system("sync")
|
|
|
|
|
|
|
|
def disable_btc_lnd_tor():
|
|
|
|
os.system("rm -f mnt/hdd/mynode/settings/.btc_lnd_tor_enabled")
|
2020-02-14 00:47:51 +00:00
|
|
|
os.system("sync")
|
|
|
|
|
|
|
|
|
|
|
|
#==================================
|
|
|
|
# Firewall Functions
|
|
|
|
#==================================
|
|
|
|
def reload_firewall():
|
|
|
|
os.system("ufw reload")
|
|
|
|
|
|
|
|
def get_firewall_rules():
|
|
|
|
try:
|
|
|
|
rules = subprocess.check_output("ufw status", shell=True).decode("utf8")
|
|
|
|
except:
|
|
|
|
rules = "ERROR"
|
|
|
|
return rules
|