mirror of
https://github.com/runcitadel/core.git
synced 2024-11-11 16:30:38 +00:00
8bcb66f0fa
* Move LND into an app * Add JWT pubkey module * Remove old LND dir * Clean up * Some cleanups * WIP: LND app * Clean up output of ls-installed * Clean up app system * Various cleanups * Fix volume name * Update dependencies.yml * Update app-manager * Fix some minor issues * Update manager * Some fixes for the LND app * Some fixes * WIP: Caddy * WIP: More https * Caddy improvements * Some more fixes * Fix caddy port * Fix for LND app * Fixes for some apps * Code cleanups * Fix entry name * Fix python * Update app-manager * Some Caddy fixes * Update app-manager * Fix tor * Fix Caddy * Fix caddy * Minor fix * Fix * Fix https * Update dependencies.yml * Fix for CLN (#1) * Update dependencies.yml * Fix Caddyfile * Expose IP address to manager * Update API * Use API from Docker Hub * Update dependencies.yml * Update dependencies.yml * Update dependencies.yml * Some fixes * Minor syntax fix * How did I even do that? * Update docker-compose.yml * Allow restarting Caddy * Add configure trigger * Replace configure with a caddy config update * Update dependencies.yml * Update Tor * Update dependencies.yml * Update dependencies.yml * Update dependencies.yml * Latest dashboard * Move to ghcr.io * Update 01-run.sh * Update 01-run.sh * Update 01-run.sh * Update dependencies.yml * Clean up * Fix mount * Update mount * Create .gitkeep * Dynamic caddy updates * Update app-cli * Update dependencies.yml * Update dependencies.yml * Remove Lightning logs from debug script * Update app manager * Clean up * Update app-cli * Citadel 0.1.8 * Remove host gateway
228 lines
8.0 KiB
Python
Executable File
228 lines
8.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# SPDX-FileCopyrightText: 2021-2023 Citadel and contributors
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import time
|
|
|
|
from lib.manage import (compose, convert_to_upper, createDataDir, deleteData,
|
|
download, downloadAll, downloadNew, get_var_safe,
|
|
getAvailableUpdates, getUserData, setInstalled,
|
|
setRemoved, update, getAppRegistryEntry)
|
|
|
|
# Print an error if user is not root
|
|
if os.getuid() != 0:
|
|
print('This script must be run as root!')
|
|
exit(1)
|
|
|
|
# The directory with this script
|
|
scriptDir = os.path.dirname(os.path.realpath(__file__))
|
|
nodeRoot = os.path.join(scriptDir, "..")
|
|
appsDir = os.path.join(nodeRoot, "apps")
|
|
appDataDir = os.path.join(nodeRoot, "app-data")
|
|
userFile = os.path.join(nodeRoot, "db", "user.json")
|
|
legacyScript = os.path.join(nodeRoot, "scripts", "app")
|
|
torDataDir = os.path.join(nodeRoot, "tor", "data")
|
|
|
|
parser = argparse.ArgumentParser(description="Manage apps on your Citadel")
|
|
parser.add_argument('action', help='What to do with the app database.', choices=[
|
|
"download", "generate", "update", "list-updates", "ls-installed", "install", "uninstall", "stop", "start", "compose", "restart", "get-ip", "get-implementation"])
|
|
parser.add_argument('--verbose', '-v', action='store_true')
|
|
parser.add_argument(
|
|
'app', help='Optional, the app to perform an action on. (For install, uninstall, stop, start and compose)', nargs='?')
|
|
parser.add_argument(
|
|
'other', help='Anything else (For compose)', nargs="*")
|
|
args = parser.parse_args()
|
|
|
|
# If no action is specified, the list action is used
|
|
if args.action is None:
|
|
args.action = 'list'
|
|
|
|
if args.action == "list-updates":
|
|
getAvailableUpdates()
|
|
exit(0)
|
|
elif args.action == 'download':
|
|
downloadAll()
|
|
exit(0)
|
|
elif args.action == 'download-new':
|
|
downloadNew()
|
|
exit(0)
|
|
elif args.action == 'generate':
|
|
update()
|
|
exit(0)
|
|
elif args.action == 'update':
|
|
if args.app is None:
|
|
downloadAll()
|
|
print("Downloaded all updates")
|
|
else:
|
|
download(args.app)
|
|
print("Downloaded latest {} version".format(args.app))
|
|
update()
|
|
exit(0)
|
|
elif args.action == 'ls-installed':
|
|
try:
|
|
# Load the userFile as JSON, check if installedApps is in it, and if so, print the apps
|
|
with open(userFile, "r") as f:
|
|
userData = json.load(f)
|
|
if "installedApps" in userData:
|
|
with open(os.path.join(appsDir, "virtual-apps.json"), "r") as f:
|
|
virtual_apps = json.load(f)
|
|
# Print the apps
|
|
# Filter out virtual apps (virtual_apps.keys())
|
|
for app in userData["installedApps"]:
|
|
if app not in virtual_apps.keys():
|
|
print(app)
|
|
else:
|
|
# To match the behavior of the old script, print a newline if there are no apps installed
|
|
print("\n")
|
|
except:
|
|
pass
|
|
elif args.action == 'install':
|
|
if not args.app:
|
|
print("No app provided")
|
|
exit(1)
|
|
registryEntry = getAppRegistryEntry(args.app)
|
|
# If registryEntry is None, fail
|
|
if registryEntry is None:
|
|
print("App {} does not seem to exist".format(args.app))
|
|
exit(1)
|
|
if isinstance(registryEntry['hiddenServices'], list):
|
|
for entry in registryEntry['hiddenServices']:
|
|
if not os.path.exists(os.path.join(torDataDir, entry, "hostname")):
|
|
print("Restarting Tor containers...")
|
|
try:
|
|
os.system("docker restart app-tor app-2-tor app-3-tor")
|
|
except:
|
|
print("Failed to restart Tor containers")
|
|
exit(1)
|
|
print("Waiting for Tor containers to restart...")
|
|
for i in range(60):
|
|
if os.path.exists(os.path.join(torDataDir, entry, "hostname")):
|
|
break
|
|
time.sleep(1)
|
|
else:
|
|
print("Tor containers did not restart in time")
|
|
exit(1)
|
|
update()
|
|
with open(os.path.join(appsDir, "virtual-apps.json"), "r") as f:
|
|
virtual_apps = json.load(f)
|
|
userData = getUserData()
|
|
implements_service = False
|
|
for virtual_app in virtual_apps.keys():
|
|
implementations = virtual_apps[virtual_app]
|
|
if args.app in implementations:
|
|
for implementation in implementations:
|
|
if "installedApps" in userData and implementation in userData["installedApps"]:
|
|
print("Another implementation of {} is already installed: {}. Uninstall it first to install this app.".format(virtual_app, implementation))
|
|
exit(1)
|
|
implements_service = virtual_app
|
|
createDataDir(args.app)
|
|
compose(args.app, "pull")
|
|
compose(args.app, "up --detach")
|
|
setInstalled(args.app)
|
|
if implements_service:
|
|
setInstalled(implements_service)
|
|
update()
|
|
|
|
elif args.action == 'uninstall':
|
|
if not args.app:
|
|
print("No app provided")
|
|
exit(1)
|
|
userData = getUserData()
|
|
if not "installedApps" in userData or args.app not in userData["installedApps"]:
|
|
print("App {} is not installed".format(args.app))
|
|
exit(1)
|
|
print("Stopping app {}...".format(args.app))
|
|
try:
|
|
compose(args.app, "rm --force --stop")
|
|
print("Deleting data...")
|
|
deleteData(args.app)
|
|
except:
|
|
pass
|
|
print("Removing from the list of installed apps...")
|
|
setRemoved(args.app)
|
|
with open(os.path.join(appsDir, "virtual-apps.json"), "r") as f:
|
|
virtual_apps = json.load(f)
|
|
implements_service = False
|
|
for virtual_app in virtual_apps.keys():
|
|
implementations = virtual_apps[virtual_app]
|
|
if args.app in implementations:
|
|
setRemoved(virtual_app)
|
|
update()
|
|
|
|
elif args.action == 'stop':
|
|
if not args.app:
|
|
print("No app provided")
|
|
exit(1)
|
|
userData = getUserData()
|
|
print("Stopping app {}...".format(args.app))
|
|
compose(args.app, "rm --force --stop")
|
|
elif args.action == 'start':
|
|
if not args.app:
|
|
print("No app provided")
|
|
exit(1)
|
|
|
|
userData = getUserData()
|
|
if not "installedApps" in userData or args.app not in userData["installedApps"]:
|
|
print("App {} is not yet installed".format(args.app))
|
|
exit(1)
|
|
compose(args.app, "up --detach")
|
|
|
|
elif args.action == 'restart':
|
|
if not args.app:
|
|
print("No app provided")
|
|
exit(1)
|
|
|
|
userData = getUserData()
|
|
if not "installedApps" in userData or args.app not in userData["installedApps"]:
|
|
print("App {} is not yet installed".format(args.app))
|
|
exit(1)
|
|
compose(args.app, "rm --force --stop")
|
|
compose(args.app, "up --detach")
|
|
|
|
elif args.action == 'compose':
|
|
if not args.app:
|
|
print("No app provided")
|
|
exit(1)
|
|
compose(args.app, " ".join(args.other))
|
|
|
|
elif args.action == "get-ip":
|
|
if args.app == "":
|
|
print("Missing app")
|
|
exit(1)
|
|
with open(os.path.join(appsDir, "virtual-apps.json"), "r") as f:
|
|
virtual_apps = json.load(f)
|
|
userData = getUserData()
|
|
implements_service = False
|
|
if args.app in virtual_apps:
|
|
for implementation in virtual_apps[args.app]:
|
|
if "installedApps" in userData and implementation in userData["installedApps"]:
|
|
print(get_var_safe("APP_{}_SERVICE_IP".format(convert_to_upper(implementation))))
|
|
exit(0)
|
|
else:
|
|
print("Not an virtual app")
|
|
exit(1)
|
|
|
|
elif args.action == "get-implementation":
|
|
if args.app == "":
|
|
print("Missing app")
|
|
exit(1)
|
|
with open(os.path.join(appsDir, "virtual-apps.json"), "r") as f:
|
|
virtual_apps = json.load(f)
|
|
userData = getUserData()
|
|
implements_service = False
|
|
if args.app in virtual_apps:
|
|
for implementation in virtual_apps[args.app]:
|
|
if "installedApps" in userData and implementation in userData["installedApps"]:
|
|
print(implementation)
|
|
exit(0)
|
|
else:
|
|
print("Not an virtual app")
|
|
exit(1)
|
|
print("Virtual app not found")
|
|
exit(1)
|