forked from michael.heier/citadel-core
Compare commits
17 Commits
stable
...
fix/revers
Author | SHA1 | Date | |
---|---|---|---|
|
5ea1d44188 | ||
|
b149564490 | ||
|
86c17c365e | ||
|
5b2b5a4541 | ||
|
6e74290691 | ||
|
62d51aa807 | ||
|
781299fa1a | ||
|
4eb9819cf9 | ||
|
9a6501a80e | ||
|
d45da547d6 | ||
|
80ead94dbd | ||
|
a5e74fa1d2 | ||
|
f6dae9c646 | ||
|
3cec30340b | ||
|
611d4a166b | ||
|
56946a9812 | ||
|
6b29a76d81 |
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -22,7 +22,7 @@ statuses/*
|
||||||
app-data
|
app-data
|
||||||
apps
|
apps
|
||||||
electrs/*
|
electrs/*
|
||||||
fulcrum/*
|
fulcrumx/*
|
||||||
nginx/*
|
nginx/*
|
||||||
redis/*
|
redis/*
|
||||||
docker-compose.override.yml
|
docker-compose.override.yml
|
||||||
|
@ -43,7 +43,7 @@ db/citadel-seed/*
|
||||||
!db/.gitkeep
|
!db/.gitkeep
|
||||||
!nginx/.gitkeep
|
!nginx/.gitkeep
|
||||||
!redis/.gitkeep
|
!redis/.gitkeep
|
||||||
!fulcrum/.gitkeep
|
!fulcrumx/.gitkeep
|
||||||
|
|
||||||
!**/*.license
|
!**/*.license
|
||||||
services/installed.json
|
services/installed.json
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
# A collection of fully FLOSS app definitions and FLOSS apps for Citadel.
|
# A collection of fully FLOSS app definitions and FLOSS apps for Citadel.
|
||||||
https://github.com/runcitadel/apps v3-stable
|
https://github.com/runcitadel/apps v3-beta
|
||||||
|
|
||||||
# Some apps modified version of Umbrel apps, and their app definitions aren't FLOSS yet.
|
# Some apps modified version of Umbrel apps, and their app definitions aren't FLOSS yet.
|
||||||
# Include them anyway, but as a separate repo.
|
# Include them anyway, but as a separate repo.
|
||||||
# Add a # to the line below to disable the repo and only use FLOSS apps.
|
# Add a # to the line below to disable the repo and only use FLOSS apps.
|
||||||
https://github.com/runcitadel/apps-nonfree v3-stable
|
https://github.com/runcitadel/apps-nonfree v3-beta
|
||||||
|
|
|
@ -47,7 +47,7 @@ def getContainerHiddenService(
|
||||||
if isinstance(container.hiddenServicePorts, int):
|
if isinstance(container.hiddenServicePorts, int):
|
||||||
return getHiddenServiceString(
|
return getHiddenServiceString(
|
||||||
"{} {}".format(metadata.name, container.name),
|
"{} {}".format(metadata.name, container.name),
|
||||||
metadata.id if isMainContainer else "{}-{}".format(metadata.id, container.name),
|
metadata.id,
|
||||||
container.hiddenServicePorts,
|
container.hiddenServicePorts,
|
||||||
containerIp,
|
containerIp,
|
||||||
container.hiddenServicePorts,
|
container.hiddenServicePorts,
|
||||||
|
@ -55,7 +55,7 @@ def getContainerHiddenService(
|
||||||
elif isinstance(container.hiddenServicePorts, list):
|
elif isinstance(container.hiddenServicePorts, list):
|
||||||
return getHiddenServiceMultiPort(
|
return getHiddenServiceMultiPort(
|
||||||
"{} {}".format(metadata.name, container.name),
|
"{} {}".format(metadata.name, container.name),
|
||||||
metadata.id if isMainContainer else "{}-{}".format(metadata.id, container.name),
|
metadata.id,
|
||||||
containerIp,
|
containerIp,
|
||||||
container.hiddenServicePorts,
|
container.hiddenServicePorts,
|
||||||
)
|
)
|
||||||
|
@ -77,14 +77,14 @@ def getContainerHiddenService(
|
||||||
else:
|
else:
|
||||||
additionalHiddenServices[key] = value
|
additionalHiddenServices[key] = value
|
||||||
for key, value in additionalHiddenServices.items():
|
for key, value in additionalHiddenServices.items():
|
||||||
|
otherHiddenServices += "\n"
|
||||||
if isinstance(value, int):
|
if isinstance(value, int):
|
||||||
otherHiddenServices += "# {} {} {} Hidden Service\nHiddenServiceDir /var/lib/tor/app-{}-{}\n".format(
|
otherHiddenServices += "# {} {} {} Hidden Service\nHiddenServiceDir /var/lib/tor/app-{}-{}\n".format(
|
||||||
metadata.name, container.name, key, metadata.id, key
|
metadata.name, container.name, key, metadata.id, container.name
|
||||||
)
|
)
|
||||||
otherHiddenServices += "HiddenServicePort {} {}:{}".format(
|
otherHiddenServices += "HiddenServicePort {} {}:{}".format(
|
||||||
value, containerIp, value
|
value, containerIp, value
|
||||||
)
|
)
|
||||||
otherHiddenServices += "\n"
|
|
||||||
elif isinstance(value, list):
|
elif isinstance(value, list):
|
||||||
otherHiddenServices += getHiddenServiceMultiPort(
|
otherHiddenServices += getHiddenServiceMultiPort(
|
||||||
"{} {}".format(metadata.name, key), "{}-{}".format(metadata.id, key), containerIp, value
|
"{} {}".format(metadata.name, key), "{}-{}".format(metadata.id, key), containerIp, value
|
||||||
|
|
|
@ -85,12 +85,11 @@ def createComposeConfigFromV3(app: dict, nodeRoot: str):
|
||||||
newApp = configureIps(newApp, networkingFile, envFile)
|
newApp = configureIps(newApp, networkingFile, envFile)
|
||||||
# This is validated earlier
|
# This is validated earlier
|
||||||
for container in newApp.containers:
|
for container in newApp.containers:
|
||||||
for tcpPort in container.requiredPorts:
|
container.ports = container.requiredPorts
|
||||||
container.ports.append("{}:{}".format(tcpPort, tcpPort))
|
|
||||||
del container.requiredPorts
|
del container.requiredPorts
|
||||||
for container in newApp.containers:
|
for container in newApp.containers:
|
||||||
for udpPort in container.requiredUdpPorts:
|
for udpPort in container.requiredUdpPorts:
|
||||||
container.ports.append("{}:{}/udp".format(udpPort, udpPort))
|
container.ports.append("{}/udp".format(udpPort))
|
||||||
del container.requiredUdpPorts
|
del container.requiredUdpPorts
|
||||||
newApp = configureMainPort(newApp, nodeRoot)
|
newApp = configureMainPort(newApp, nodeRoot)
|
||||||
newApp = configureHiddenServices(newApp, nodeRoot)
|
newApp = configureHiddenServices(newApp, nodeRoot)
|
||||||
|
|
|
@ -77,8 +77,6 @@ def configureMainPort(app: AppStage2, nodeRoot: str) -> AppStage3:
|
||||||
# If it doesn't contain a :, it's the port itself
|
# If it doesn't contain a :, it's the port itself
|
||||||
if mainPort == False:
|
if mainPort == False:
|
||||||
mainPort = mainContainer.ports[0]
|
mainPort = mainContainer.ports[0]
|
||||||
if mainPort.find(":") != -1:
|
|
||||||
mainPort = mainPort.split(":")[1]
|
|
||||||
else:
|
else:
|
||||||
mainContainer.ports = [portToAppend]
|
mainContainer.ports = [portToAppend]
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,26 @@ def getUserData():
|
||||||
userData = json.load(f)
|
userData = json.load(f)
|
||||||
return userData
|
return userData
|
||||||
|
|
||||||
|
def checkUpdateAvailable(name: str) -> bool:
|
||||||
|
latestAppYml = yaml.safe_load(getAppYml(name))
|
||||||
|
with open(os.path.join(appsDir, name, "app.yml"), "r") as f:
|
||||||
|
originalAppYml = yaml.safe_load(f)
|
||||||
|
if not "metadata" in latestAppYml or not "version" in latestAppYml["metadata"] or not "metadata" in originalAppYml or not "version" in originalAppYml["metadata"]:
|
||||||
|
print("App {} is not valid".format(name))
|
||||||
|
return False
|
||||||
|
return semver.compare(latestAppYml["metadata"]["version"], originalAppYml["metadata"]["version"]) > 0
|
||||||
|
|
||||||
|
def getAvailableUpdates():
|
||||||
|
availableUpdates = []
|
||||||
|
apps = findAndValidateApps(appsDir)
|
||||||
|
for app in apps:
|
||||||
|
try:
|
||||||
|
if checkUpdateAvailable(app):
|
||||||
|
availableUpdates.append(app)
|
||||||
|
except Exception:
|
||||||
|
print("Warning: Can't check app {} yet".format(app), file=sys.stderr)
|
||||||
|
return availableUpdates
|
||||||
|
|
||||||
def startInstalled():
|
def startInstalled():
|
||||||
# If userfile doesn't exist, just do nothing
|
# If userfile doesn't exist, just do nothing
|
||||||
userData = {}
|
userData = {}
|
||||||
|
@ -344,59 +364,3 @@ def updateRepos():
|
||||||
shutil.rmtree(tempDir)
|
shutil.rmtree(tempDir)
|
||||||
with open(os.path.join(appsDir, "sourceMap.json"), "w") as f:
|
with open(os.path.join(appsDir, "sourceMap.json"), "w") as f:
|
||||||
json.dump(sourceMap, f)
|
json.dump(sourceMap, f)
|
||||||
|
|
||||||
|
|
||||||
def getAvailableUpdates():
|
|
||||||
availableUpdates = {}
|
|
||||||
repos = []
|
|
||||||
ignoreApps = []
|
|
||||||
with open(sourcesList) as f:
|
|
||||||
repos = f.readlines()
|
|
||||||
try:
|
|
||||||
with open(updateIgnore) as f:
|
|
||||||
ignoreApps = f.readlines()
|
|
||||||
except: pass
|
|
||||||
# For each repo, clone the repo to a temporary dir, checkout the branch,
|
|
||||||
# and overwrite the current app dir with the contents of the temporary dir/apps/app
|
|
||||||
# Set this to ignoreApps. Normally, it keeps track of apps already installed from repos higher in the list,
|
|
||||||
# but apps specified in updateignore have the highest priority
|
|
||||||
alreadyDefined = [s.strip() for s in ignoreApps]
|
|
||||||
for repo in repos:
|
|
||||||
repo = repo.strip()
|
|
||||||
if repo == "":
|
|
||||||
continue
|
|
||||||
# Also ignore comments
|
|
||||||
if repo.startswith("#"):
|
|
||||||
continue
|
|
||||||
# Split the repo into the git url and the branch
|
|
||||||
repo = repo.split(" ")
|
|
||||||
if len(repo) != 2:
|
|
||||||
print("Error: Invalid repo format in " + sourcesList, file=sys.stderr)
|
|
||||||
exit(1)
|
|
||||||
gitUrl = repo[0]
|
|
||||||
branch = repo[1]
|
|
||||||
# Clone the repo to a temporary dir
|
|
||||||
tempDir = tempfile.mkdtemp()
|
|
||||||
# Git clone with a depth of 1 to avoid cloning the entire repo
|
|
||||||
# Don't print anything to stdout, as we don't want to see the git clone output
|
|
||||||
subprocess.run("git clone --depth 1 --branch {} {} {}".format(branch, gitUrl, tempDir), shell=True, stdout=subprocess.DEVNULL)
|
|
||||||
# Overwrite the current app dir with the contents of the temporary dir/apps/app
|
|
||||||
for app in os.listdir(os.path.join(tempDir, "apps")):
|
|
||||||
try:
|
|
||||||
# if the app is already installed (or a simple file instead of a valid app), skip it
|
|
||||||
if app in alreadyDefined or not os.path.isdir(os.path.join(tempDir, "apps", app)):
|
|
||||||
continue
|
|
||||||
with open(os.path.join(appsDir, app, "app.yml"), "r") as f:
|
|
||||||
originalAppYml = yaml.safe_load(f)
|
|
||||||
with open(os.path.join(tempDir, "apps", app, "app.yml"), "r") as f:
|
|
||||||
latestAppYml = yaml.safe_load(f)
|
|
||||||
if semver.compare(latestAppYml["metadata"]["version"], originalAppYml["metadata"]["version"]) > 0:
|
|
||||||
availableUpdates[app] = {
|
|
||||||
"updateFrom": originalAppYml["metadata"]["version"],
|
|
||||||
"updateTo": latestAppYml["metadata"]["version"]
|
|
||||||
}
|
|
||||||
except Exception:
|
|
||||||
print("Warning: Can't check app {} (yet)".format(app), file=sys.stderr)
|
|
||||||
# Remove the temporary dir
|
|
||||||
shutil.rmtree(tempDir)
|
|
||||||
return availableUpdates
|
|
||||||
|
|
|
@ -7,18 +7,18 @@ import yaml
|
||||||
from jsonschema import validate
|
from jsonschema import validate
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
scriptDir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")
|
|
||||||
|
|
||||||
with open(os.path.join(scriptDir, 'app-standard-v1.yml'), 'r') as f:
|
|
||||||
schemaVersion1 = yaml.safe_load(f)
|
|
||||||
with open(os.path.join(scriptDir, 'app-standard-v2.yml'), 'r') as f:
|
|
||||||
schemaVersion2 = yaml.safe_load(f)
|
|
||||||
with open(os.path.join(scriptDir, 'app-standard-v3.yml'), 'r') as f:
|
|
||||||
schemaVersion3 = yaml.safe_load(f)
|
|
||||||
|
|
||||||
# Validates app data
|
# Validates app data
|
||||||
# Returns true if valid, false otherwise
|
# Returns true if valid, false otherwise
|
||||||
|
scriptDir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")
|
||||||
def validateApp(app: dict):
|
def validateApp(app: dict):
|
||||||
|
with open(os.path.join(scriptDir, 'app-standard-v1.yml'), 'r') as f:
|
||||||
|
schemaVersion1 = yaml.safe_load(f)
|
||||||
|
with open(os.path.join(scriptDir, 'app-standard-v2.yml'), 'r') as f:
|
||||||
|
schemaVersion2 = yaml.safe_load(f)
|
||||||
|
with open(os.path.join(scriptDir, 'app-standard-v3.yml'), 'r') as f:
|
||||||
|
schemaVersion3 = yaml.safe_load(f)
|
||||||
|
|
||||||
if 'version' in app and str(app['version']) == "1":
|
if 'version' in app and str(app['version']) == "1":
|
||||||
try:
|
try:
|
||||||
validate(app, schemaVersion1)
|
validate(app, schemaVersion1)
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../cli/citadel
|
|
|
@ -13,7 +13,7 @@ CITADEL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
|
||||||
result=$(docker compose \
|
result=$(docker compose \
|
||||||
--file "${CITADEL_ROOT}/docker-compose.yml" \
|
--file "${CITADEL_ROOT}/docker-compose.yml" \
|
||||||
--env-file "${CITADEL_ROOT}/.env" \
|
--env-file "${CITADEL_ROOT}/.env" \
|
||||||
exec lightning lncli "$@")
|
exec lnd lncli "$@")
|
||||||
|
|
||||||
# We need to echo with quotes to preserve output formatting
|
# We need to echo with quotes to preserve output formatting
|
||||||
echo "$result"
|
echo "$result"
|
||||||
|
|
487
cli/citadel
487
cli/citadel
|
@ -1,487 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2022 Citadel and contributors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
CITADEL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
|
|
||||||
CLI_NAME="$(basename $0)"
|
|
||||||
CLI_VERSION="0.0.1"
|
|
||||||
CLI_DIR="$(dirname "$(readlink -f "$0")")"
|
|
||||||
SERVICE_NAME="citadel-startup"
|
|
||||||
EDITOR="${EDITOR:-micro}"
|
|
||||||
|
|
||||||
source $CLI_DIR/utils/functions.sh
|
|
||||||
source $CLI_DIR/utils/multiselect.sh
|
|
||||||
source $CLI_DIR/utils/spinner.sh
|
|
||||||
source $CLI_DIR/utils/helpers.sh
|
|
||||||
|
|
||||||
if [ -z ${1+x} ]; then
|
|
||||||
command=""
|
|
||||||
else
|
|
||||||
command="$1"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check Citadel Status
|
|
||||||
if [[ "$command" = "status" ]]; then
|
|
||||||
POSITIONAL_ARGS=()
|
|
||||||
|
|
||||||
long=false
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case $1 in
|
|
||||||
-l | --long)
|
|
||||||
long=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-* | --*)
|
|
||||||
echo "Unknown option $1"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
POSITIONAL_ARGS+=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
set -- "${POSITIONAL_ARGS[@]}"
|
|
||||||
|
|
||||||
free -m | awk 'NR==2{printf "Memory Usage: %s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2 }'
|
|
||||||
df -h | awk '$NF=="/"{printf "Disk Usage: %d/%dGB (%s)\n", $3,$2,$5}'
|
|
||||||
top -bn1 | grep load | awk '{printf "CPU Load: %.2f\n", $(NF-2)}'
|
|
||||||
|
|
||||||
echo
|
|
||||||
|
|
||||||
if $long; then
|
|
||||||
docker container ls --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
|
|
||||||
else
|
|
||||||
docker container ls --format "table {{.Names}}\t{{.Status}}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $(pgrep -f karen) ]]; then
|
|
||||||
printf "\nKaren is listening.\n"
|
|
||||||
else
|
|
||||||
printf "\nERROR: Karen is not listening.\n"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update Citadel
|
|
||||||
if [[ "$command" = "update" ]]; then
|
|
||||||
POSITIONAL_ARGS=()
|
|
||||||
|
|
||||||
branch=$(get_update_channel)
|
|
||||||
force=false
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case $1 in
|
|
||||||
-b | --branch)
|
|
||||||
branch="$2"
|
|
||||||
shift # past argument
|
|
||||||
shift # past value
|
|
||||||
;;
|
|
||||||
--force)
|
|
||||||
force=true
|
|
||||||
shift # past argument
|
|
||||||
;;
|
|
||||||
-* | --*)
|
|
||||||
echo "Unknown option $1"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
POSITIONAL_ARGS+=("$1") # save positional arg
|
|
||||||
shift # past argument
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters
|
|
||||||
|
|
||||||
if $force; then
|
|
||||||
sudo rm -f $CITADEL_ROOT/statuses/update-in-progress
|
|
||||||
fi
|
|
||||||
|
|
||||||
sudo $CITADEL_ROOT/scripts/update/update --repo runcitadel/core#$branch
|
|
||||||
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Start Citadel
|
|
||||||
if [[ "$command" = "start" ]]; then
|
|
||||||
if $(is_managed_by_systemd); then
|
|
||||||
if $(is_service_active); then
|
|
||||||
echo 'Citadel is already running.'
|
|
||||||
else
|
|
||||||
sudo systemctl start citadel-startup
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
sudo $CITADEL_ROOT/scripts/start
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Stop Citadel
|
|
||||||
if [[ "$command" = "stop" ]]; then
|
|
||||||
active=$(is_service_active)
|
|
||||||
|
|
||||||
if $(is_managed_by_systemd) && $active; then
|
|
||||||
if $(is_service_active); then
|
|
||||||
sudo systemctl stop citadel-startup
|
|
||||||
else
|
|
||||||
echo 'Citadel is not running.'
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
sudo $CITADEL_ROOT/scripts/stop
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Restart Citadel
|
|
||||||
if [[ "$command" = "restart" ]]; then
|
|
||||||
shift
|
|
||||||
|
|
||||||
# TODO: enable restarting services
|
|
||||||
|
|
||||||
if [ ! -z ${1+x} ]; then
|
|
||||||
echo "Too many arguments."
|
|
||||||
echo "Usage: \`$CLI_NAME $command\`"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $(is_managed_by_systemd); then
|
|
||||||
sudo systemctl restart $SERVICE_NAME
|
|
||||||
else
|
|
||||||
sudo $CITADEL_ROOT/scripts/stop
|
|
||||||
sudo $CITADEL_ROOT/scripts/start
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Reboot the system
|
|
||||||
if [[ "$command" = "reboot" ]]; then
|
|
||||||
$CLI_NAME stop || true
|
|
||||||
sudo reboot
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Shutdown the system
|
|
||||||
if [[ "$command" = "shutdown" ]]; then
|
|
||||||
$CLI_NAME stop || true
|
|
||||||
sudo shutdown now
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# List all installed services apps
|
|
||||||
if [[ "$command" = "list" ]]; then
|
|
||||||
echo 'karen'
|
|
||||||
docker ps --format "{{.Names}}"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run a command inside a container
|
|
||||||
if [[ "$command" = "run" ]]; then
|
|
||||||
shift
|
|
||||||
|
|
||||||
if [ -z ${1+x} ]; then
|
|
||||||
echo "Specify an app or service."
|
|
||||||
echo "Usage: \`$CLI_NAME $command <service> \"<command>\"\`"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z ${2+x} ]; then
|
|
||||||
echo "Specify a command to run."
|
|
||||||
echo "Usage: \`$CLI_NAME $command <service> \"<command>\"\`"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker exec -t $1 sh -c "$2" || {
|
|
||||||
echo "To see all installed services & apps use \`$CLI_NAME list\`"
|
|
||||||
echo "Usage: \`$CLI_NAME $command <service> \"<command>\"\`"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Configure Citadel
|
|
||||||
if [[ "$command" = "set" ]]; then
|
|
||||||
shift
|
|
||||||
|
|
||||||
if [ -z ${1+x} ]; then
|
|
||||||
echo "Missing subcommand."
|
|
||||||
echo "Usage: \`$CLI_NAME $command <subcommand>\`"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
subcommand="$1"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Switch update channel
|
|
||||||
if [[ "$subcommand" = "update-channel" ]]; then
|
|
||||||
if [ -z ${2+x} ]; then
|
|
||||||
echo "Specify an update channel to switch to."
|
|
||||||
echo "Usage: \`$CLI_NAME $subcommand <stable|beta|c-lightning>\`"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
case $2 in "stable" | "beta" | "c-lightning")
|
|
||||||
# continue
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Not a valid update channel: \"$2\""
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
sudo $CITADEL_ROOT/scripts/set-update-channel $2
|
|
||||||
$CLI_NAME update
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Switch Bitcoin/Electrum implementation
|
|
||||||
if [[ "$subcommand" = "implementation" ]] || [[ "$subcommand" = "impl" ]]; then
|
|
||||||
shift
|
|
||||||
sudo $CITADEL_ROOT/services/manage.py set $@
|
|
||||||
$CLI_NAME restart
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Switch Bitcoin network
|
|
||||||
if [[ "$subcommand" = "network" ]]; then
|
|
||||||
shift
|
|
||||||
|
|
||||||
if [ -z ${1+x} ]; then
|
|
||||||
echo "Specify a network to switch to."
|
|
||||||
echo "Usage: \`$CLI_NAME $subcommand <mainnet|signet|testnet|regtest>\`"
|
|
||||||
else
|
|
||||||
case $1 in
|
|
||||||
"mainnet" | "testnet" | "signet" | "regtest")
|
|
||||||
sudo $CITADEL_ROOT/scripts/stop
|
|
||||||
sudo OVERWRITE_NETWORK=$1 $CITADEL_ROOT/scripts/configure
|
|
||||||
sudo $CITADEL_ROOT/scripts/start
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Not a valid value for network"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "\"$subcommand\" is not a valid subcommand."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# App commands
|
|
||||||
if [[ "$command" = "app" ]]; then
|
|
||||||
shift
|
|
||||||
sudo $CITADEL_ROOT/scripts/app $@
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Edit common app configuration files
|
|
||||||
if [[ "$command" = "configure" ]]; then
|
|
||||||
if [ -z ${2+x} ]; then
|
|
||||||
echo "Specify an app or service to configure."
|
|
||||||
echo "Usage: \`$CLI_NAME $command <service>\`"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
POSITIONAL_ARGS=()
|
|
||||||
|
|
||||||
persist=false
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case $1 in
|
|
||||||
--persist)
|
|
||||||
persist=true
|
|
||||||
shift # past argument
|
|
||||||
;;
|
|
||||||
-* | --*)
|
|
||||||
echo "Unknown option $1"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
POSITIONAL_ARGS+=("$1") # save positional arg
|
|
||||||
shift # past argument
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters
|
|
||||||
|
|
||||||
# These service and app configs are already persisted
|
|
||||||
# TODO: add more apps
|
|
||||||
|
|
||||||
if [[ "$2" = "nextcloud" ]]; then
|
|
||||||
edit_file --priviledged $CITADEL_ROOT/app-data/nextcloud/data/nextcloud/config/config.php
|
|
||||||
prompt_apply_config nextcloud-web-1 false
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$2" = "nginx" ]]; then
|
|
||||||
edit_file $CITADEL_ROOT/nginx/nginx.conf
|
|
||||||
prompt_apply_config nginx false
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $persist; then
|
|
||||||
echo "NOTE: As of now persisted config changes will not be kept when updating Citadel."
|
|
||||||
else
|
|
||||||
echo "NOTE: Some changes to this configuration file may be overwritten the next time you start Citadel."
|
|
||||||
echo "To persist the changes run the command again with \`$CLI_NAME configure $2 --persist\`"
|
|
||||||
fi
|
|
||||||
|
|
||||||
read -p "Continue? [Y/n] " should_continue
|
|
||||||
echo
|
|
||||||
if [[ $should_continue =~ [Nn]$ ]]; then
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Service and app configs below may be overwritten
|
|
||||||
# TODO: check which implementation is running
|
|
||||||
# and do "bitcoin" / "lightning" / "electrum"
|
|
||||||
|
|
||||||
if [[ "$2" = "bitcoin" ]]; then
|
|
||||||
if $persist; then
|
|
||||||
edit_file $CITADEL_ROOT/templates/bitcoin-sample.conf
|
|
||||||
prompt_apply_config bitcoin true
|
|
||||||
else
|
|
||||||
edit_file $CITADEL_ROOT/bitcoin/bitcoin.conf
|
|
||||||
prompt_apply_config bitcoin false
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$2" = "lnd" ]]; then
|
|
||||||
if $persist; then
|
|
||||||
edit_file $CITADEL_ROOT/templates/lnd-sample.conf
|
|
||||||
prompt_apply_config lightning true
|
|
||||||
else
|
|
||||||
edit_file $CITADEL_ROOT/lnd/lnd.conf
|
|
||||||
prompt_apply_config lightning false
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$2" = "electrs" ]]; then
|
|
||||||
edit_file $CITADEL_ROOT/templates/electrs-sample.toml
|
|
||||||
prompt_apply_config electrum true
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$2" = "fulcrum" ]]; then
|
|
||||||
if $persist; then
|
|
||||||
edit_file $CITADEL_ROOT/templates/fulcrum-sample.conf
|
|
||||||
prompt_apply_config electrum true
|
|
||||||
else
|
|
||||||
edit_file $CITADEL_ROOT/fulcrum/fulcrum.conf
|
|
||||||
prompt_apply_config electrum false
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "No service or app \"$2\" not found."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Show logs for apps & services
|
|
||||||
if [[ "$command" = "logs" ]]; then
|
|
||||||
shift
|
|
||||||
|
|
||||||
POSITIONAL_ARGS=()
|
|
||||||
|
|
||||||
follow=false
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case $1 in
|
|
||||||
-f | --follow)
|
|
||||||
follow=true
|
|
||||||
shift # past argument
|
|
||||||
;;
|
|
||||||
-n | --tail)
|
|
||||||
number_of_lines="$2"
|
|
||||||
shift # past argument
|
|
||||||
shift # past value
|
|
||||||
;;
|
|
||||||
-* | --*)
|
|
||||||
echo "Unknown option $1"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
POSITIONAL_ARGS+=("$1") # save positional arg
|
|
||||||
shift # past argument
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters
|
|
||||||
|
|
||||||
# Set default number_of_lines if not set by user
|
|
||||||
if [ -z ${number_of_lines+x} ]; then
|
|
||||||
if [[ ${#POSITIONAL_ARGS[@]} == 0 ]] || [[ ${#POSITIONAL_ARGS[@]} == 1 ]]; then
|
|
||||||
number_of_lines=40
|
|
||||||
else
|
|
||||||
number_of_lines=10
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z ${1+x} ] || [[ "$1" = "karen" ]]; then
|
|
||||||
if [[ ${#POSITIONAL_ARGS[@]} == 2 ]]; then
|
|
||||||
echo "Karen logs cannot be viewed together with other services."
|
|
||||||
echo "Usage: \`$CLI_NAME $command karen\`"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
tail $($follow && echo "-f") -n $number_of_lines $CITADEL_ROOT/logs/karen.log
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#POSITIONAL_ARGS[@]} == 1 ]]; then
|
|
||||||
docker logs $($follow && echo "-f") --tail $number_of_lines $@ || {
|
|
||||||
echo "To see all installed services & apps use \`$CLI_NAME list\`"
|
|
||||||
echo "Usage: \`$CLI_NAME $command <service>\`"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
else
|
|
||||||
# TODO: can only show logs for services in docker-compose.yml
|
|
||||||
docker compose logs $($follow && echo "-f") --tail $number_of_lines $@ || {
|
|
||||||
echo "To see all installed services & apps use \`$CLI_NAME list\`"
|
|
||||||
echo "Usage: \`$CLI_NAME $command <service>\`"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Debug Citadel
|
|
||||||
if [[ "$command" = "debug" ]]; then
|
|
||||||
shift
|
|
||||||
sudo $CITADEL_ROOT/scripts/debug $@
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Show version information for this CLI
|
|
||||||
if [[ "$command" = "--version" ]] || [[ "$command" = "-v" ]]; then
|
|
||||||
citadel_version=$(jq -r '.version' $CITADEL_ROOT/info.json)
|
|
||||||
echo "Citadel v$citadel_version"
|
|
||||||
echo "citadel-cli v$CLI_VERSION"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Show usage information for this CLI
|
|
||||||
if [[ "$command" = "--help" ]] || [[ "$command" = "-h" ]]; then
|
|
||||||
show_help
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If we get here it means no valid command was supplied
|
|
||||||
# Show help and exit
|
|
||||||
show_help
|
|
||||||
exit
|
|
|
@ -1,111 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
show_help() {
|
|
||||||
cat <<EOF
|
|
||||||
${CLI_NAME}-cli v${CLI_VERSION}
|
|
||||||
Manage your Citadel.
|
|
||||||
|
|
||||||
Usage: ${CLI_NAME} <command> [options]
|
|
||||||
|
|
||||||
Flags:
|
|
||||||
-h, --help Show this help message
|
|
||||||
-v, --version Show version information for this CLI
|
|
||||||
|
|
||||||
Commands:
|
|
||||||
status Check the status of all services
|
|
||||||
start Start the Citadel service
|
|
||||||
stop Stop the Citadel service safely
|
|
||||||
restart Restart the Citadel service
|
|
||||||
reboot Reboot the system
|
|
||||||
shutdown Shutdown the system
|
|
||||||
update Update Citadel
|
|
||||||
list List all installed services apps
|
|
||||||
run <service> "<command>" Run a command inside a container
|
|
||||||
set <command> Switch between Bitcoin & Lightning implementations
|
|
||||||
app <command> Install, update or restart apps
|
|
||||||
configure <service> Edit service & app configuration files
|
|
||||||
logs <service> Show logs for an app or service
|
|
||||||
debug View logs for troubleshooting
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
is_managed_by_systemd() {
|
|
||||||
if systemctl --all --type service | grep -q "$SERVICE_NAME"; then
|
|
||||||
echo true
|
|
||||||
else
|
|
||||||
echo false
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
is_service_active() {
|
|
||||||
service_status=$(systemctl is-active $SERVICE_NAME)
|
|
||||||
if [[ "$service_status" = "active" ]]; then
|
|
||||||
echo true
|
|
||||||
else
|
|
||||||
echo false
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
edit_file() {
|
|
||||||
if [[ $1 = "--priviledged" ]]; then
|
|
||||||
echo "Editing this file requires elevated priviledges."
|
|
||||||
|
|
||||||
if ! sudo test -f $2; then
|
|
||||||
echo "File not found."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if sudo test -w $2; then
|
|
||||||
sudo $EDITOR $2
|
|
||||||
else
|
|
||||||
echo "File not writable."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if ! test -f $1; then
|
|
||||||
echo "File not found."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -w $1; then
|
|
||||||
$EDITOR $1
|
|
||||||
else
|
|
||||||
echo "File not writable."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
get_update_channel() {
|
|
||||||
update_channel_line=$(cat $CITADEL_ROOT/.env | grep UPDATE_CHANNEL)
|
|
||||||
update_channel=(${update_channel_line//=/ })
|
|
||||||
|
|
||||||
if [ -z ${update_channel[1]+x} ]; then
|
|
||||||
# fall back to stable
|
|
||||||
echo "stable"
|
|
||||||
else
|
|
||||||
echo ${update_channel[1]}
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
prompt_apply_config() {
|
|
||||||
service=$1
|
|
||||||
persisted=$2
|
|
||||||
|
|
||||||
read -p "Do you want to apply the changes now? [y/N] " should_restart
|
|
||||||
echo
|
|
||||||
if [[ $should_restart =~ [Yy]$ ]]; then
|
|
||||||
if $persisted; then
|
|
||||||
sudo $CITADEL_ROOT/scripts/configure
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf "\nRestarting service \"$service\"...\n"
|
|
||||||
docker restart $service
|
|
||||||
echo "Done."
|
|
||||||
else
|
|
||||||
if $persisted; then
|
|
||||||
echo "To apply the changes, restart Citadel by running \`$CLI_NAME restart\`."
|
|
||||||
else
|
|
||||||
echo "To apply the changes, restart service \"$service\" by running \`docker restart $service\`."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
trim() {
|
|
||||||
local var="$*"
|
|
||||||
# remove leading whitespace characters
|
|
||||||
var="${var#"${var%%[![:space:]]*}"}"
|
|
||||||
# remove trailing whitespace characters
|
|
||||||
var="${var%"${var##*[![:space:]]}"}"
|
|
||||||
printf '%s' "$var"
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
function multiselect() {
|
|
||||||
# little helpers for terminal print control and key input
|
|
||||||
ESC=$(printf "\033")
|
|
||||||
cursor_blink_on() { printf "$ESC[?25h"; }
|
|
||||||
cursor_blink_off() { printf "$ESC[?25l"; }
|
|
||||||
cursor_to() { printf "$ESC[$1;${2:-1}H"; }
|
|
||||||
print_inactive() { printf "$2 $1 "; }
|
|
||||||
print_active() { printf "$2 $ESC[7m $1 $ESC[27m"; }
|
|
||||||
get_cursor_row() {
|
|
||||||
IFS=';' read -sdR -p $'\E[6n' ROW COL
|
|
||||||
echo ${ROW#*[}
|
|
||||||
}
|
|
||||||
|
|
||||||
local return_value=$1
|
|
||||||
local -n options=$2
|
|
||||||
local -n defaults=$3
|
|
||||||
|
|
||||||
local selected=()
|
|
||||||
for ((i = 0; i < ${#options[@]}; i++)); do
|
|
||||||
if [[ ${defaults[i]} = "true" ]]; then
|
|
||||||
selected+=("true")
|
|
||||||
else
|
|
||||||
selected+=("false")
|
|
||||||
fi
|
|
||||||
printf "\n"
|
|
||||||
done
|
|
||||||
|
|
||||||
# determine current screen position for overwriting the options
|
|
||||||
local lastrow=$(get_cursor_row)
|
|
||||||
local startrow=$(($lastrow - ${#options[@]}))
|
|
||||||
|
|
||||||
# ensure cursor and input echoing back on upon a ctrl+c during read -s
|
|
||||||
trap "cursor_blink_on; stty echo; printf '\n'; exit" 2
|
|
||||||
cursor_blink_off
|
|
||||||
|
|
||||||
key_input() {
|
|
||||||
local key
|
|
||||||
IFS= read -rsn1 key 2>/dev/null >&2
|
|
||||||
if [[ $key = "" ]]; then echo enter; fi
|
|
||||||
if [[ $key = $'\x20' ]]; then echo space; fi
|
|
||||||
if [[ $key = "k" ]]; then echo up; fi
|
|
||||||
if [[ $key = "j" ]]; then echo down; fi
|
|
||||||
if [[ $key = $'\x1b' ]]; then
|
|
||||||
read -rsn2 key
|
|
||||||
if [[ $key = [A || $key = k ]]; then echo up; fi
|
|
||||||
if [[ $key = [B || $key = j ]]; then echo down; fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle_option() {
|
|
||||||
local option=$1
|
|
||||||
if [[ ${selected[option]} == true ]]; then
|
|
||||||
selected[option]=false
|
|
||||||
else
|
|
||||||
selected[option]=true
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
print_options() {
|
|
||||||
# print options by overwriting the last lines
|
|
||||||
local idx=0
|
|
||||||
|
|
||||||
for option in "${options[@]}"; do
|
|
||||||
local prefix="[ ]"
|
|
||||||
|
|
||||||
if [[ ${selected[idx]} == true ]]; then
|
|
||||||
prefix="[\e[38;5;46m✔\e[0m]"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cursor_to $(($startrow + $idx))
|
|
||||||
if [ $idx -eq $1 ]; then
|
|
||||||
print_active "$option" "$prefix"
|
|
||||||
else
|
|
||||||
print_inactive "$option" "$prefix"
|
|
||||||
fi
|
|
||||||
|
|
||||||
idx=$((idx + 1))
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
get_result() {
|
|
||||||
local result=()
|
|
||||||
for ((i = 0; i < ${#options[@]}; i++)); do
|
|
||||||
if ${selected[i]}; then
|
|
||||||
result+=(${options[i]})
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "${result[@]}"
|
|
||||||
}
|
|
||||||
|
|
||||||
local active=0
|
|
||||||
while true; do
|
|
||||||
print_options $active
|
|
||||||
|
|
||||||
# user key control
|
|
||||||
case $(key_input) in
|
|
||||||
space) toggle_option $active ;;
|
|
||||||
enter)
|
|
||||||
print_options -1
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
up)
|
|
||||||
active=$((active - 1))
|
|
||||||
if [ $active -lt 0 ]; then active=$((${#options[@]} - 1)); fi
|
|
||||||
;;
|
|
||||||
down)
|
|
||||||
active=$((active + 1))
|
|
||||||
if [ $active -ge ${#options[@]} ]; then active=0; fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# cursor position back to normal
|
|
||||||
cursor_to $lastrow
|
|
||||||
printf "\n"
|
|
||||||
cursor_blink_on
|
|
||||||
|
|
||||||
eval $return_value='("$(get_result)")'
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Author: Tasos Latsas
|
|
||||||
|
|
||||||
# spinner.sh
|
|
||||||
#
|
|
||||||
# Display an awesome 'spinner' while running your long shell commands
|
|
||||||
#
|
|
||||||
# Do *NOT* call _spinner function directly.
|
|
||||||
# Use {start,stop}_spinner wrapper functions
|
|
||||||
|
|
||||||
# usage:
|
|
||||||
# 1. source this script in your's
|
|
||||||
# 2. start the spinner:
|
|
||||||
# start_spinner [display-message-here]
|
|
||||||
# 3. run your command
|
|
||||||
# 4. stop the spinner:
|
|
||||||
# stop_spinner [your command's exit status]
|
|
||||||
#
|
|
||||||
# Also see: test.sh
|
|
||||||
|
|
||||||
function _spinner() {
|
|
||||||
# $1 start/stop
|
|
||||||
#
|
|
||||||
# on start: $2 display message
|
|
||||||
# on stop : $2 process exit status
|
|
||||||
# $3 spinner function pid (supplied from stop_spinner)
|
|
||||||
|
|
||||||
local on_success="DONE"
|
|
||||||
local on_fail="FAIL"
|
|
||||||
local white="\e[1;37m"
|
|
||||||
local green="\e[1;32m"
|
|
||||||
local red="\e[1;31m"
|
|
||||||
local nc="\e[0m"
|
|
||||||
|
|
||||||
case $1 in
|
|
||||||
start)
|
|
||||||
# display message with some space
|
|
||||||
echo -ne "${2} "
|
|
||||||
|
|
||||||
# start spinner
|
|
||||||
i=1
|
|
||||||
sp='\|/-'
|
|
||||||
delay=${SPINNER_DELAY:-0.15}
|
|
||||||
|
|
||||||
while :; do
|
|
||||||
printf "\b${sp:i++%${#sp}:1}"
|
|
||||||
sleep $delay
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
if [[ -z ${3} ]]; then
|
|
||||||
echo "spinner is not running.."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
kill $3 >/dev/null 2>&1
|
|
||||||
|
|
||||||
# inform the user upon success or failure
|
|
||||||
echo -en "\b["
|
|
||||||
if [[ $2 -eq 0 ]]; then
|
|
||||||
echo -en "${green}${on_success}${nc}"
|
|
||||||
else
|
|
||||||
echo -en "${red}${on_fail}${nc}"
|
|
||||||
fi
|
|
||||||
echo -e "]"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "invalid argument, try {start/stop}"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
function start_spinner() {
|
|
||||||
# $1 : msg to display
|
|
||||||
_spinner "start" "${1}" &
|
|
||||||
# set global spinner pid
|
|
||||||
_sp_pid=$!
|
|
||||||
disown
|
|
||||||
}
|
|
||||||
|
|
||||||
function stop_spinner() {
|
|
||||||
# $1 : command exit status
|
|
||||||
_spinner "stop" $1 $_sp_pid
|
|
||||||
unset _sp_pid
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@ version: '3.8'
|
||||||
services:
|
services:
|
||||||
tor:
|
tor:
|
||||||
container_name: tor
|
container_name: tor
|
||||||
image: lncm/tor:0.4.7.8@sha256:aab30ebb496aa25934d6096951d8b200347c3c3ce5db3493695229efa2601f7b
|
image: lncm/tor:0.4.7.7@sha256:3c4ae833d2fefbea7d960f833a1e89fc9b2069a6e5f360109b5ddc9334ac0227
|
||||||
user: toruser
|
user: toruser
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -15,7 +15,7 @@ services:
|
||||||
ipv4_address: $TOR_PROXY_IP
|
ipv4_address: $TOR_PROXY_IP
|
||||||
app-tor:
|
app-tor:
|
||||||
container_name: app-tor
|
container_name: app-tor
|
||||||
image: lncm/tor:0.4.7.8@sha256:aab30ebb496aa25934d6096951d8b200347c3c3ce5db3493695229efa2601f7b
|
image: lncm/tor:0.4.7.7@sha256:3c4ae833d2fefbea7d960f833a1e89fc9b2069a6e5f360109b5ddc9334ac0227
|
||||||
user: toruser
|
user: toruser
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -26,7 +26,7 @@ services:
|
||||||
ipv4_address: $APPS_TOR_IP
|
ipv4_address: $APPS_TOR_IP
|
||||||
app-2-tor:
|
app-2-tor:
|
||||||
container_name: app-2-tor
|
container_name: app-2-tor
|
||||||
image: lncm/tor:0.4.7.8@sha256:aab30ebb496aa25934d6096951d8b200347c3c3ce5db3493695229efa2601f7b
|
image: lncm/tor:0.4.7.7@sha256:3c4ae833d2fefbea7d960f833a1e89fc9b2069a6e5f360109b5ddc9334ac0227
|
||||||
user: toruser
|
user: toruser
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -37,7 +37,7 @@ services:
|
||||||
ipv4_address: $APPS_2_TOR_IP
|
ipv4_address: $APPS_2_TOR_IP
|
||||||
app-3-tor:
|
app-3-tor:
|
||||||
container_name: app-3-tor
|
container_name: app-3-tor
|
||||||
image: lncm/tor:0.4.7.8@sha256:aab30ebb496aa25934d6096951d8b200347c3c3ce5db3493695229efa2601f7b
|
image: lncm/tor:0.4.7.7@sha256:3c4ae833d2fefbea7d960f833a1e89fc9b2069a6e5f360109b5ddc9334ac0227
|
||||||
user: toruser
|
user: toruser
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -65,7 +65,7 @@ services:
|
||||||
ipv4_address: $NGINX_IP
|
ipv4_address: $NGINX_IP
|
||||||
bitcoin:
|
bitcoin:
|
||||||
container_name: bitcoin
|
container_name: bitcoin
|
||||||
image: ghcr.io/runcitadel/bitcoinknots:main@sha256:5fbee0f6f0d09d42aacc11c373ffe6162210c42ce21e6eba294e547e3ad80219
|
image: nolim1t/bitcoinknots:v22.0.knots20211108@sha256:a475da2b2ecda55fcc65ea23e1a36c58b2c10549f1c3d3bb3c31c7dda1127354
|
||||||
depends_on:
|
depends_on:
|
||||||
- tor
|
- tor
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -79,7 +79,7 @@ services:
|
||||||
ipv4_address: $BITCOIN_IP
|
ipv4_address: $BITCOIN_IP
|
||||||
lightning:
|
lightning:
|
||||||
container_name: lightning
|
container_name: lightning
|
||||||
image: lightninglabs/lnd:v0.15.0-beta@sha256:d227a9db0727ff56020c8d6604c8c369757123d238ab6ce679579c2dd0d0d259
|
image: lightninglabs/lnd:v0.14.3-beta@sha256:6a2234b0aad4caed3d993736816b198d6228f32c59b27ba2218d5ebf516ae905
|
||||||
user: 1000:1000
|
user: 1000:1000
|
||||||
depends_on:
|
depends_on:
|
||||||
- tor
|
- tor
|
||||||
|
@ -100,7 +100,7 @@ services:
|
||||||
ipv4_address: $LND_IP
|
ipv4_address: $LND_IP
|
||||||
dashboard:
|
dashboard:
|
||||||
container_name: dashboard
|
container_name: dashboard
|
||||||
image: ghcr.io/runcitadel/dashboard:v0.0.15@sha256:a2cf5ad79367fb083db0f61e5a296aafee655c99af0c228680644c248ec674a5
|
image: ghcr.io/runcitadel/dashboard:v0.0.12@sha256:102a44b938765be8224c63785949b90bf796670f01aef4e282d58a4c26a42595
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
stop_grace_period: 1m30s
|
stop_grace_period: 1m30s
|
||||||
networks:
|
networks:
|
||||||
|
@ -108,7 +108,7 @@ services:
|
||||||
ipv4_address: $DASHBOARD_IP
|
ipv4_address: $DASHBOARD_IP
|
||||||
manager:
|
manager:
|
||||||
container_name: manager
|
container_name: manager
|
||||||
image: ghcr.io/runcitadel/manager:v0.0.15@sha256:9fb5a86d9e40a04f93d5b6110d43a0f9a5c4ad6311a843b5442290013196a5ce
|
image: ghcr.io/runcitadel/manager:v0.0.13@sha256:3ced2643e12253fea46abb48a69dcd999d69d3d86ed9956ae0298d4f6be4f06d
|
||||||
depends_on:
|
depends_on:
|
||||||
- tor
|
- tor
|
||||||
- redis
|
- redis
|
||||||
|
@ -162,7 +162,7 @@ services:
|
||||||
ipv4_address: $MANAGER_IP
|
ipv4_address: $MANAGER_IP
|
||||||
middleware:
|
middleware:
|
||||||
container_name: middleware
|
container_name: middleware
|
||||||
image: ghcr.io/runcitadel/middleware:v0.0.11@sha256:e472da8cbfa67d9a9dbf321334fe65cdf20a0f9b6d6bab33fdf07210f54e7002
|
image: ghcr.io/runcitadel/middleware:v0.0.10@sha256:afd6e2b6f5ba27cde32f6f6d630ddc6dd46d1072871f7834d7424d0554d0f53d
|
||||||
depends_on:
|
depends_on:
|
||||||
- manager
|
- manager
|
||||||
- bitcoin
|
- bitcoin
|
||||||
|
|
|
@ -6,4 +6,4 @@
|
||||||
|
|
||||||
CITADEL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/../..)"
|
CITADEL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/../..)"
|
||||||
|
|
||||||
"${CITADEL_ROOT}/scripts/set-update-channel" "${1}"
|
"${CITADEL_ROOT}/scripts/set-update-channel" beta
|
9
events/triggers/use-stable-builds
Executable file
9
events/triggers/use-stable-builds
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: 2021-2022 Citadel and contributors
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
CITADEL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/../..)"
|
||||||
|
|
||||||
|
"${CITADEL_ROOT}/scripts/set-update-channel" stable
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"version": "0.0.7",
|
"version": "0.0.4-rc.1",
|
||||||
"name": "Citadel 0.0.7",
|
"name": "Citadel 0.0.4 Release Candidate 1",
|
||||||
"requires": ">=0.0.1",
|
"requires": ">=0.0.1",
|
||||||
"notes": "While we are busy with the next huge update, you may need to wait longer for updates. This update updates Bitcoin Knots and LND to their latest versions to ensure apps can utilize their latest features. In addition, this update includes the Citadel CLI. More information on that will be published soon."
|
"notes": "This update fixes multiple bugs in the 0.0.4 release."
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,11 +53,17 @@ with open(registry_file) as file:
|
||||||
|
|
||||||
port = None
|
port = None
|
||||||
for app in registry:
|
for app in registry:
|
||||||
if app['name'] == service:
|
if app['id'] == service:
|
||||||
if "internalPort" in app:
|
if "internalPort" in app:
|
||||||
port = app['internalPort']
|
port = app['internalPort']
|
||||||
|
else:
|
||||||
|
port = app['port']
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if port is None:
|
||||||
|
print("No port found!")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
original_config = crossplane.parse(nginx_config_file)
|
original_config = crossplane.parse(nginx_config_file)
|
||||||
parsedConfig = original_config["config"][0]["parsed"]
|
parsedConfig = original_config["config"][0]["parsed"]
|
||||||
|
|
||||||
|
@ -70,14 +76,6 @@ ip_alt_env_var = "APP_{}_MAIN_IP".format(
|
||||||
service.upper().replace("-", "_")
|
service.upper().replace("-", "_")
|
||||||
)
|
)
|
||||||
|
|
||||||
port_env_var = "APP_{}_WEB_PORT".format(
|
|
||||||
service.upper().replace("-", "_")
|
|
||||||
)
|
|
||||||
|
|
||||||
port_alt_env_var = "APP_{}_MAIN_PORT".format(
|
|
||||||
service.upper().replace("-", "_")
|
|
||||||
)
|
|
||||||
|
|
||||||
env = parse_dotenv(os.path.join(node_root, '.env'))
|
env = parse_dotenv(os.path.join(node_root, '.env'))
|
||||||
|
|
||||||
ip=None
|
ip=None
|
||||||
|
@ -89,21 +87,6 @@ else:
|
||||||
print("Error: No IP found for {}".format(service))
|
print("Error: No IP found for {}".format(service))
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if port == None:
|
|
||||||
if port_env_var in env:
|
|
||||||
port = env[port_env_var]
|
|
||||||
elif port_alt_env_var in env:
|
|
||||||
port = env[port_alt_env_var]
|
|
||||||
else:
|
|
||||||
print("Error: No port found for {}".format(service))
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if service == "btcpay-server":
|
|
||||||
port = 1234
|
|
||||||
|
|
||||||
if service == "lnme":
|
|
||||||
port = 1323
|
|
||||||
|
|
||||||
actual_url="http://{}:{}".format(ip, port)
|
actual_url="http://{}:{}".format(ip, port)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2020 Umbrel. https://getumbrel.com
|
# SPDX-FileCopyrightText: 2020 Umbrel. https://getumbrel.com
|
||||||
# SPDX-FileCopyrightText: 2022 Citadel and contributors. https://runcitadel.space
|
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
@ -99,19 +98,39 @@ tar \
|
||||||
# --verbose \
|
# --verbose \
|
||||||
# --gzip
|
# --gzip
|
||||||
|
|
||||||
|
# Check if a file exists on Firebase by checking if
|
||||||
|
# "https://firebasestorage.googleapis.com/v0/b/citadel-user-backups.appspot.com/o/backups%2F<THE_FILE_NAME>?alt=media"
|
||||||
|
# returns a 200 response code.
|
||||||
|
#
|
||||||
|
check_if_exists() {
|
||||||
|
curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-X GET \
|
||||||
|
"https://firebasestorage.googleapis.com/v0/b/citadel-user-backups.appspot.com/o/backups%2F${1}?alt=media"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Upload a file to Firebase Cloud Storage by uloading its name + a random ID.
|
||||||
|
# Before uploading, we need to check if a file with the same name already exists, and if it does, change the random ID.
|
||||||
|
# For example, if we want to upload a file named "<THE_FILE_NAME>" with the content AA, we'd use this command to upload:
|
||||||
|
# curl -X POST "https://firebasestorage.googleapis.com/v0/b/citadel-user-backups.appspot.com/o/backups%2F<THE_FILE_NAME>?alt=media" -d "AA" -H "Content-Type: text/plain"
|
||||||
|
# To check if a file exists, we can check if this endpoint returns an error 404:
|
||||||
|
# curl "https://firebasestorage.googleapis.com/v0/b/citadel-user-backups.appspot.com/o/backups%2F<THE_FILE_NAME>?alt=media"
|
||||||
|
# To download a file, we can the same endpoint
|
||||||
upload_file() {
|
upload_file() {
|
||||||
local file_to_send="${1}"
|
local file_to_send="${1}"
|
||||||
local backup_id="${2}"
|
local file_name="${2}"
|
||||||
local upload_data=$(jq --null-input \
|
# A random ID to avoid collisions
|
||||||
--arg name "$backup_id" \
|
local random_id="$(tr -dc A-Za-z0-9 </dev/urandom | head -c 60 ; echo '')"
|
||||||
--arg data "$(base64 $file_to_send)" \
|
# Check if the file already exists
|
||||||
'{"name": $name, "data": $data}')
|
# While a file with the same name exists, we'll try to upload it with a different ID
|
||||||
|
while [[ $(check_if_exists "${file_name}-${random_id}") == "200" ]]; do
|
||||||
|
random_id="$(tr -dc A-Za-z0-9 </dev/urandom | head -c 60 ; echo '')"
|
||||||
|
done
|
||||||
|
# Upload the file
|
||||||
curl -X POST \
|
curl -X POST \
|
||||||
"https://account.runcitadel.space/api/upload" \
|
"https://firebasestorage.googleapis.com/v0/b/citadel-user-backups.appspot.com/o/backups%2F${file_name}-${random_id}?alt=media" \
|
||||||
-d "${upload_data}" \
|
-d @"${file_to_send}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/octet-stream" \
|
||||||
--socks5 "localhost:${TOR_PROXY_PORT}" \
|
> /dev/null
|
||||||
> /dev/null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ $BITCOIN_NETWORK == "testnet" ]]; then
|
if [[ $BITCOIN_NETWORK == "testnet" ]]; then
|
||||||
|
|
2
scripts/configure
vendored
2
scripts/configure
vendored
|
@ -334,7 +334,7 @@ templates_to_build = {
|
||||||
"./templates/bitcoin-sample.conf": "./bitcoin/bitcoin.conf",
|
"./templates/bitcoin-sample.conf": "./bitcoin/bitcoin.conf",
|
||||||
"./templates/.env-sample": "./.env",
|
"./templates/.env-sample": "./.env",
|
||||||
"./templates/electrs-sample.toml": "./electrs/electrs.toml",
|
"./templates/electrs-sample.toml": "./electrs/electrs.toml",
|
||||||
"./templates/fulcrum-sample.conf": "./fulcrum/fulcrum.conf",
|
"./templates/fulcrumx-sample.conf": "./fulcrumx/fulcrumx.conf",
|
||||||
"./templates/nginx-sample.conf": "./nginx/nginx.conf"
|
"./templates/nginx-sample.conf": "./nginx/nginx.conf"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,17 +21,7 @@ function get_memory_usage() {
|
||||||
function mem_usage_to_percent() {
|
function mem_usage_to_percent() {
|
||||||
local mem_usage="$1"
|
local mem_usage="$1"
|
||||||
local total_mem="$(free -m | awk 'NR==2 {print $2}')"
|
local total_mem="$(free -m | awk 'NR==2 {print $2}')"
|
||||||
echo "$(awk "BEGIN {printf \"%.1f\", ${mem_usage/,/.} / ${total_mem/,/.} * 100}")"
|
echo "$(awk "BEGIN {printf \"%.1f\", $mem_usage / $total_mem * 100}")"
|
||||||
}
|
|
||||||
|
|
||||||
function app_mem_usage() {
|
|
||||||
# For every container of the app, get the mem usage, save it, and at the end, print the total mem usage of the app
|
|
||||||
local mem_usage=0
|
|
||||||
for container in $(get_app_containers "$1"); do
|
|
||||||
# Use awk to add, it supports floating point numbers
|
|
||||||
mem_usage=$(awk "BEGIN {printf \"%.2f\", $mem_usage + $(get_memory_usage "$container")}")
|
|
||||||
done
|
|
||||||
echo "${1}: $mem_usage%"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_total_used_mem_raw() {
|
get_total_used_mem_raw() {
|
||||||
|
@ -45,7 +35,7 @@ get_total_used_mem() {
|
||||||
# To get the containers of the app, list every container whose name starts with the name of the app
|
# To get the containers of the app, list every container whose name starts with the name of the app
|
||||||
get_app_containers () {
|
get_app_containers () {
|
||||||
local app_name="$1"
|
local app_name="$1"
|
||||||
"${CITADEL_ROOT}/scripts/app" compose "${app_name}" ps | awk '{print $1}' | grep -v 'NAME'
|
"${CITADEL_ROOT}/scripts/app" compose "${app_name}" ps | awk '{print $1}' | grep -v 'Name\|-----'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get the memory usage of the whole system, excluding docker containers
|
# Get the memory usage of the whole system, excluding docker containers
|
||||||
|
@ -58,17 +48,22 @@ get_system_memory_usage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
echo "total: $(get_total_used_mem)%"
|
echo "total: $(get_total_used_mem)%"&
|
||||||
echo "system: $(get_system_memory_usage)%"
|
|
||||||
for service in bitcoin lightning electrum tor; do
|
for service in bitcoin lightning electrum tor; do
|
||||||
echo "${service}: $(get_memory_usage "$service")%" &
|
echo "${service}: $(get_memory_usage "$service")%" &
|
||||||
done
|
done
|
||||||
for app in $("${CITADEL_ROOT}/scripts/app" ls-installed); do
|
for app in $("${CITADEL_ROOT}/scripts/app" ls-installed); do
|
||||||
app_mem_usage "${app}" &
|
# For every container of the app, get the mem usage, save it, and at the end, print the total mem usage of the app
|
||||||
|
local mem_usage=0
|
||||||
|
for container in $(get_app_containers "$app"); do
|
||||||
|
# Use awk to add, it supports floating point numbers
|
||||||
|
mem_usage=$(awk "BEGIN {printf \"%.2f\", $mem_usage + $(get_memory_usage "$container")}")
|
||||||
|
done
|
||||||
|
wait
|
||||||
|
echo "${app}: $mem_usage%"
|
||||||
done
|
done
|
||||||
|
echo "system: $(get_system_memory_usage)%"
|
||||||
wait
|
wait
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "Calculating memory usage..."
|
|
||||||
echo "This may take a while, please wait..."
|
|
||||||
main | sort --key 2 --numeric-sort --reverse
|
main | sort --key 2 --numeric-sort --reverse
|
||||||
|
|
|
@ -90,11 +90,11 @@ echo
|
||||||
echo "Starting status monitors..."
|
echo "Starting status monitors..."
|
||||||
echo
|
echo
|
||||||
pkill -f ./scripts/status-monitor || true
|
pkill -f ./scripts/status-monitor || true
|
||||||
./scripts/status-monitor memory 300 &>> "${CITADEL_LOGS}/status-monitor.log" &
|
./scripts/status-monitor memory 60 &>> "${CITADEL_LOGS}/status-monitor.log" &
|
||||||
./scripts/status-monitor storage 60 &>> "${CITADEL_LOGS}/status-monitor.log" &
|
./scripts/status-monitor storage 60 &>> "${CITADEL_LOGS}/status-monitor.log" &
|
||||||
./scripts/status-monitor temperature 15 &>> "${CITADEL_LOGS}/status-monitor.log" &
|
./scripts/status-monitor temperature 15 &>> "${CITADEL_LOGS}/status-monitor.log" &
|
||||||
./scripts/status-monitor uptime 15 &>> "${CITADEL_LOGS}/status-monitor.log" &
|
./scripts/status-monitor uptime 15 &>> "${CITADEL_LOGS}/status-monitor.log" &
|
||||||
./scripts/status-monitor app-updates 600 &>> "${CITADEL_LOGS}/status-monitor.log" &
|
./scripts/status-monitor app-updates 300 &>> "${CITADEL_LOGS}/status-monitor.log" &
|
||||||
|
|
||||||
echo "Starting backup monitor..."
|
echo "Starting backup monitor..."
|
||||||
echo
|
echo
|
||||||
|
|
|
@ -4,9 +4,6 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
# To prevent tools we use from outputting in another language
|
|
||||||
LANG=C
|
|
||||||
|
|
||||||
CITADEL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/../..)"
|
CITADEL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/../..)"
|
||||||
|
|
||||||
memory_total_bytes() {
|
memory_total_bytes() {
|
||||||
|
@ -26,7 +23,7 @@ get_app_memory_use() {
|
||||||
|
|
||||||
local app_memory=0
|
local app_memory=0
|
||||||
|
|
||||||
local app_containers=$("${CITADEL_ROOT}/scripts/app" compose "${app}" ps | awk '{print $1}' | grep -v 'NAME')
|
local app_containers=$("${CITADEL_ROOT}/app/app-manager.py" compose "${app}" ps | awk '{print $1}' | grep -v 'Name\|-----')
|
||||||
for container in $app_containers; do
|
for container in $app_containers; do
|
||||||
local container_memory=$(get_container_memory_use "${container}")
|
local container_memory=$(get_container_memory_use "${container}")
|
||||||
app_memory=$(awk "BEGIN {print ${app_memory}+${container_memory}}")
|
app_memory=$(awk "BEGIN {print ${app_memory}+${container_memory}}")
|
||||||
|
@ -46,7 +43,7 @@ used=$(memory_used_bytes)
|
||||||
json=$(echo $json | jq --arg used "${used}" '. + {used: $used|tonumber}')
|
json=$(echo $json | jq --arg used "${used}" '. + {used: $used|tonumber}')
|
||||||
|
|
||||||
cumulative_app_memory="0"
|
cumulative_app_memory="0"
|
||||||
for app in $( "${CITADEL_ROOT}/scripts/app" ls-installed); do
|
for app in $( "${CITADEL_ROOT}/app/app-manager.py" ls-installed); do
|
||||||
app_memory=$(get_app_memory_use "${app}")
|
app_memory=$(get_app_memory_use "${app}")
|
||||||
cumulative_app_memory=$(($cumulative_app_memory+$app_memory))
|
cumulative_app_memory=$(($cumulative_app_memory+$app_memory))
|
||||||
json=$(echo $json | jq --arg app "${app}" --arg app_memory "${app_memory}" '.breakdown |= .+ [{id: $app, used: $app_memory|tonumber}]')
|
json=$(echo $json | jq --arg app "${app}" --arg app_memory "${app_memory}" '.breakdown |= .+ [{id: $app, used: $app_memory|tonumber}]')
|
||||||
|
|
|
@ -12,4 +12,4 @@ nginx/*
|
||||||
services/installed.yml
|
services/installed.yml
|
||||||
apps/sourceMap.json
|
apps/sourceMap.json
|
||||||
apps/.updateignore
|
apps/.updateignore
|
||||||
fulcrum/*
|
fulcrumx/*
|
||||||
|
|
18
services/bitcoin/citadel.yml
Normal file
18
services/bitcoin/citadel.yml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# SPDX-FileCopyrightText: 2021-2022 Citadel and contributors
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
bitcoin:
|
||||||
|
container_name: bitcoin
|
||||||
|
image: ghcr.io/runcitadel/bitcoin-custom:main@sha256:d0af506f8dc92a434e845305ac4252d0601b699c4b3bc4443073a0a2e237f3a0
|
||||||
|
depends_on:
|
||||||
|
- tor
|
||||||
|
volumes:
|
||||||
|
- ${PWD}/bitcoin:/data/.bitcoin
|
||||||
|
restart: on-failure
|
||||||
|
stop_grace_period: 1m
|
||||||
|
ports:
|
||||||
|
- $BITCOIN_P2P_PORT:$BITCOIN_P2P_PORT
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
ipv4_address: $BITCOIN_IP
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
bitcoin:
|
bitcoin:
|
||||||
container_name: bitcoin
|
container_name: bitcoin
|
||||||
image: lncm/bitcoind:v23.0@sha256:57317c90d89156a30327fe1b8e51b836e0fd1a8ba13721eb2e75e6b35a570e26
|
image: lncm/bitcoind:v22.0@sha256:37a1adb29b3abc9f972f0d981f45e41e5fca2e22816a023faa9fdc0084aa4507
|
||||||
depends_on:
|
depends_on:
|
||||||
- tor
|
- tor
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
bitcoin:
|
bitcoin:
|
||||||
container_name: bitcoin
|
container_name: bitcoin
|
||||||
image: ghcr.io/runcitadel/bitcoinknots:main@sha256:5fbee0f6f0d09d42aacc11c373ffe6162210c42ce21e6eba294e547e3ad80219
|
image: nolim1t/bitcoinknots:v22.0.knots20211108@sha256:a475da2b2ecda55fcc65ea23e1a36c58b2c10549f1c3d3bb3c31c7dda1127354
|
||||||
depends_on:
|
depends_on:
|
||||||
- tor
|
- tor
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
|
|
||||||
electrum:
|
electrum:
|
||||||
container_name: electrum
|
container_name: electrum
|
||||||
image: cculianu/fulcrum:latest@sha256:c0543f8b8a5bf6b0c447d8525d6b4360a6c07532f7741f19cc2c179968e71848
|
image: ghcr.io/runcitadel/fulcrumx:latest@sha256:a74abdfe8397f02482faed6bd828477c452df071129f66ad6596d0ab8d29cf39
|
||||||
working_dir: /data
|
working_dir: /data
|
||||||
volumes:
|
volumes:
|
||||||
- ${PWD}/bitcoin:/bitcoin:ro
|
- ${PWD}/bitcoin:/bitcoin:ro
|
||||||
- ${PWD}/fulcrum:/data
|
- ${PWD}/fulcrumx:/data
|
||||||
command: /usr/bin/Fulcrum /data/fulcrum.conf
|
command: /usr/bin/FulcrumX /data/fulcrumx.conf
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
stop_grace_period: 5m
|
stop_grace_period: 5m
|
||||||
ports:
|
ports:
|
19
services/electrum/fulcrumx.yml
Normal file
19
services/electrum/fulcrumx.yml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# SPDX-FileCopyrightText: 2021-2022 Citadel and contributors
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
electrum:
|
||||||
|
container_name: electrum
|
||||||
|
image: ghcr.io/runcitadel/fulcrumx:latest@sha256:557a54a5652b475b01c59eb6cffee3568f18b74d875c4cc125e5ac190c4b0706
|
||||||
|
working_dir: /data
|
||||||
|
volumes:
|
||||||
|
- ${PWD}/bitcoin:/bitcoin:ro
|
||||||
|
- ${PWD}/fulcrumx:/data
|
||||||
|
command: /usr/bin/FulcrumX /data/fulcrumx.conf
|
||||||
|
restart: on-failure
|
||||||
|
stop_grace_period: 5m
|
||||||
|
ports:
|
||||||
|
- "$ELECTRUM_PORT:$ELECTRUM_PORT"
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
ipv4_address: $ELECTRUM_IP
|
|
@ -1,6 +1,6 @@
|
||||||
lightning:
|
lightning:
|
||||||
container_name: lightning
|
container_name: lightning
|
||||||
image: lightninglabs/lnd:v0.15.0-beta@sha256:d227a9db0727ff56020c8d6604c8c369757123d238ab6ce679579c2dd0d0d259
|
image: lightninglabs/lnd:v0.14.3-beta@sha256:6a2234b0aad4caed3d993736816b198d6228f32c59b27ba2218d5ebf516ae905
|
||||||
user: 1000:1000
|
user: 1000:1000
|
||||||
depends_on:
|
depends_on:
|
||||||
- tor
|
- tor
|
||||||
|
|
|
@ -31,21 +31,6 @@ args = parser.parse_args()
|
||||||
# Function to install a service
|
# Function to install a service
|
||||||
# To install it, read the service's YAML file (nodeRoot/services/name.yml) and add it to the main compose file (nodeRoot/docker-compose.yml)
|
# To install it, read the service's YAML file (nodeRoot/services/name.yml) and add it to the main compose file (nodeRoot/docker-compose.yml)
|
||||||
def setService(name, implementation):
|
def setService(name, implementation):
|
||||||
# Get all available services
|
|
||||||
services = next(os.walk(os.path.join(nodeRoot, "services")))[1]
|
|
||||||
|
|
||||||
if not name in services:
|
|
||||||
print("\"{}\" is not a valid service.".format(name))
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# Get all available implementations
|
|
||||||
implementations = next(os.walk(os.path.join(nodeRoot, "services", name)), (None, None, []))[2]
|
|
||||||
implementations = [x.split('.')[0] for x in implementations]
|
|
||||||
|
|
||||||
if not implementation in implementations:
|
|
||||||
print("\"{}\" is not a valid implementation.".format(implementation))
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# Read the YAML file
|
# Read the YAML file
|
||||||
with open(os.path.join(nodeRoot, "services", name, implementation + ".yml"), 'r') as stream:
|
with open(os.path.join(nodeRoot, "services", name, implementation + ".yml"), 'r') as stream:
|
||||||
service = yaml.safe_load(stream)
|
service = yaml.safe_load(stream)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user