Add dynamic app uninstall

This commit is contained in:
Taylor Helsper 2022-06-23 22:48:55 -05:00
parent ca5072a63e
commit 35d310c23c
11 changed files with 169 additions and 77 deletions

View File

@ -50,6 +50,8 @@ def main():
elif args.command == "install" or \
args.command == "upgrade" or \
args.command == "reinstall":
# If no app name, install all
# Re-install requires app name (from above)
app_names = args.app
if not isinstance(app_names, list):
app_names = [app_names]
@ -58,12 +60,14 @@ def main():
clear_installed_version(app_name)
upgrade_dynamic_apps()
elif args.command == "upgrade":
# If no app name, upgrade all
app_names = args.app
if not isinstance(app_names, list):
app_names = [app_names]
for app_name in app_names:
upgrade_dynamic_apps(app_name)
elif args.command == "uninstall":
# Requires specified application
app_names = args.app
for app_name in app_names:
uninstall_dynamic_app(app_name)

View File

@ -68,9 +68,11 @@ else
echo "No custom uninstall steps"
fi
# Attempt generic uninstall
rm -rf /opt/mynode/${APP}
# Attempt dynamic app uninstall
mynode-manage-apps uninstall "$APP"
# Remove app folder
rm -rf /opt/mynode/${APP}
chown -R admin:admin /home/admin/upgrade_logs
sync

View File

@ -1,13 +1,10 @@
echo "UNINSTALLING LNDG - START"
echo "UNINSTALLING APP - START"
whoami
id
echo "This is the custom uninstall script for lndg!"
# The app folder will be removed automatically after this script runs.
sleep 3s
# You may not need to do anything here. You can backup data to the data folder, but
# that is ideally setup via symlinks during application install. Otherwise, re-flashing
# the SD card would lose data.
pwd
ls -lsa
sleep 3s
echo "UNINSTALLING LNDG - END"
echo "UNINSTALLING APP - END"

View File

@ -0,0 +1,3 @@
Custom Jinja templates (HTML files) can be added here for unique application pages
Templates will be available under applications/<short_name>/xyz.html

View File

@ -656,6 +656,10 @@ def init_dynamic_app(app_info):
if (os.path.isfile(app_dir+"/nginx/https_"+app_name+".conf")):
os.system("cp -f {} {}".format(app_dir+"/nginx/https_"+app_name+".conf", "/etc/nginx/sites-enabled/https_"+app_name+".conf"))
# TODO: Install web files
# Install python files www/python/*.py (<short_name>.py required)
# Install templates www/templates/*.html (optional)
# For "node" type apps
log_message(" TODO: Need node special files???")
@ -748,15 +752,38 @@ def upgrade_dynamic_apps(short_name="all"):
log_message(" ERROR: Error checking app {} for upgrade ({})".format(app_name, str(e)))
# Typically, the mynode_uninstall_app.sh runs first and calls mynode-manage-apps uninstall to run this
# Prior to running, service should have been stopped and disabled
# Post running, the app install folder will be deleted (not the storage folder on data drive)
# HOWEVER! To make sure running this alone works if managing apps via the CLI, those actions are repeated
def uninstall_dynamic_app(short_name):
print("Uninstalling app {}...".format(short_name))
if not is_application_valid(short_name):
app_data = get_application(short_name)
if app_data == None:
print(" Invalid app: {}".format(short_name))
exit(1)
print(" NOT IMPLEMENTED")
# TODO
# Run general uninstall script?
# Disable service file
# Run app-specific uninstall script
uninstall_script = "/bin/bash /usr/bin/service_scripts/install_{}.sh".format(short_name)
if os.path.isfile(uninstall_script):
try:
my_env = os.environ.copy()
my_env["VERSION"] = app_data["latest_version"]
my_env["INSTALL_FOLDER"] = app_data["install_folder"]
my_env["STORAGE_FOLDER"] = app_data["storage_folder"]
if app_data["install_env_vars"]:
for key in app_data["install_env_vars"]:
my_env[key] = app_data["install_env_vars"][key]
subprocess.check_output("cd {}; sudo -u {} /bin/bash /usr/bin/service_scripts/uninstall_{}.sh 1>&2".format(app_data["install_folder"], app_data["linux_user"], short_name), shell=True, env=my_env)
except Exception as e:
print(" Exception: {}".format(str(e)))
# Disable service
disable_service(short_name)
# Delete SD card folder
pass
run_linux_cmd("rm -rf {}".format(app_data["install_folder"]))
# Clear app data
clear_application_cache()

View File

@ -48,4 +48,64 @@ function openConfirmDialog(divid, title, message, okFunction) {
function showAlertPopup(divid, message) {
$("#"+divid).html(message);
$("#"+divid).show().delay(3000).fadeOut();
}
// Check if using tor
function is_using_tor() {
if (location.hostname.includes(".onion")) {
return true;
}
return false;
}
// Open new tab
function open_new_mynode_tab(port, protocol="same") {
hostname=location.hostname
if (protocol == "same") {
protocol = location.protocol
} else if (protocol == "http" || protocol == "https") {
protocol = protocol + ":"
}
url = protocol+'//'+hostname+':'+port
window.open(url,'_blank');
}
// Open app in new tab
function open_app_in_new_tab(http_port, https_port="NA", requires_https=false, custom_tor_address="NA", tor_http_port="80", tor_https_port="443") {
protocol=location.protocol
hostname=location.hostname
port_string=""
if (is_using_tor() && custom_tor_address != "NA") {
hostname=custom_tor_address
// Use "default" port - either 80 or 443 for HTTP/HTTPS unless overriden
if (protocol == "http:" && tor_http_port != "80") {
port_string=":"+tor_http_port
}
if (protocol == "https:" && tor_https_port != "443") {
port_string=":"+tor_https_port
}
// If app is HTTP only
if (tor_https_port == "NA") {
protocol = "http:"
port_string = ":"+tor_http_port
}
} else {
if (protocol == "http:" && http_port != "80") {
port_string=":"+http_port
}
if (protocol == "https:" && https_port != "443") {
port_string=":"+https_port
}
// If app is HTTP only
if (https_port == "NA") {
protocol = "http:"
port_string = ":"+http_port
}
}
url = protocol+'//'+hostname+port_string
window.open(url,'_blank');
}

View File

@ -0,0 +1,51 @@
<!DOCTYPE html lang="en">
<head>
<title>myNode - {{app.name}}</title>
{% include 'includes/head.html' %}
</head>
<body>
{% include 'includes/logo_header.html' %}
<div class="mynode_back_div">
<a class="ui-button ui-widget ui-corner-all mynode_back" href="/"><span class="ui-icon ui-icon-home"></span>home&nbsp;</a>
</div>
<div class="main_header">{{app.name}}</div>
<br/>
<div class="app_tile_row">
<div class="info_tile">
<div class="info_tile_header">Status</div>
<div class="info_tile_contents">
<table class="info_table">
<tr>
<th>Status</th>
<td>{{whirlpool_status}}</td>
</tr>
{% if whirlpool_enabled and whirlpool_initialized %}
<tr>
<th>API Key for Whirlpool GUI</th>
<td>{{whirlpool_api_key}}</td>
</tr>
{% endif %}
<tr>
<th>Actions</th>
<td>
FILL IN BUTTONS?
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="instructions">
<div class="instructions-header">Instructions to setup APPLICATION / DESCRIPTION</div>
<ol class="instructions-steps">
<li>AAAAAAAA</li>
<li>BBBBBBBBBBB</li>
<li>Enjoy!</li>
</ol>
</div>
</body>
</html>

View File

@ -0,0 +1,3 @@
FOLDERS AND FILES IN THIS FOLDER ARE DYNAMICALLY ADDED
Do not edit files within this folder. They will be overwritten during app install process.

View File

@ -231,63 +231,6 @@
}
showing_lightning_details = !showing_lightning_details;
}
function is_using_tor() {
if (location.hostname.includes(".onion")) {
return true;
}
return false;
}
function open_new_mynode_tab(port, protocol="same") {
hostname=location.hostname
if (protocol == "same") {
protocol = location.protocol
} else if (protocol == "http" || protocol == "https") {
protocol = protocol + ":"
}
url = protocol+'//'+hostname+':'+port
window.open(url,'_blank');
}
function open_app_in_new_tab(http_port, https_port="NA", requires_https=false, custom_tor_address="NA", tor_http_port="80", tor_https_port="443") {
protocol=location.protocol
hostname=location.hostname
port_string=""
if (is_using_tor() && custom_tor_address != "NA") {
hostname=custom_tor_address
// Use "default" port - either 80 or 443 for HTTP/HTTPS unless overriden
if (protocol == "http:" && tor_http_port != "80") {
port_string=":"+tor_http_port
}
if (protocol == "https:" && tor_https_port != "443") {
port_string=":"+tor_https_port
}
// If app is HTTP only
if (tor_https_port == "NA") {
protocol = "http:"
port_string = ":"+tor_http_port
}
} else {
if (protocol == "http:" && http_port != "80") {
port_string=":"+http_port
}
if (protocol == "https:" && https_port != "443") {
port_string=":"+https_port
}
// If app is HTTP only
if (https_port == "NA") {
protocol = "http:"
port_string = ":"+http_port
}
}
url = protocol+'//'+hostname+port_string
window.open(url,'_blank');
}
// Update page function

View File

@ -21,10 +21,11 @@
// Redirect to home
setTimeout(redirectHome, 2500)
} else {
if ("uptime_seconds" in data) {
if (data && "uptime_seconds" in data) {
if (uptime == null || data["uptime_seconds"] > uptime) {
uptime = data["uptime_seconds"]
} else if (data["uptime_seconds"] < uptime) {
//alert("Restarting due to uptime A (" + data["uptime_seconds"] + " < " + uptime + ")")
setTimeout(redirectHome, 2500)
}
}
@ -35,10 +36,11 @@
// Redirect to home
setTimeout(redirectHome, 2500)
} else {
if ("uptime_seconds" in data) {
if (data && "uptime_seconds" in data) {
if (uptime == null || data["uptime_seconds"] > uptime) {
uptime = data["uptime_seconds"]
} else if (data["uptime_seconds"] < uptime) {
//alert("Restarting due to uptime B (" + data["uptime_seconds"] + " < " + uptime + ")")
setTimeout(redirectHome, 2500)
}
}