From 4b8c42bedd0dca7ca92d69288ddf32d762397908 Mon Sep 17 00:00:00 2001 From: Aaron Dewes Date: Sun, 20 Mar 2022 09:02:30 +0100 Subject: [PATCH 1/3] Citadel 0.0.2 (#17) * Start working on Fulcrum support * More work on fulcrum/electrs switching * Some fixes * Update FulcrumX * Some fixes * Some FulcrumX fixes * Fixes for apps which use the host network * More fixes for host mode apps * Stop installed apps during update * More work on service managment * Update docker-compose * Update FulcrumX * Fix update channel script * Update manager to 0.0.6 * add network settings for new UI (development) * set DEVICE_HOSTNAME env var * clean up println statements * build: don't run manager & middleware as root * build: update core images * Update some containers * Improve app manager wrapper script * Fix stop script * Add WIP release notes for 0.0.2 * More improvements to the app CLI * More information for c-lightning users * Update dashboard to 0.0.9 * Start cleaning the ports list * More cleanups to the reserved ports list * fix: update lightning container name * Update manager Co-authored-by: Philipp Walter --- .gitignore | 5 +- .../composegenerator/v1/utils/networking.py | 40 +++++++++++- app/lib/composegenerator/v2/networking.py | 9 ++- docker-compose.yml | 28 ++++---- fulcrumx/.gitkeep | 0 info.json | 6 +- scripts/app | 19 +++++- scripts/configure | 64 +++++++------------ scripts/set-update-channel | 2 +- scripts/start | 2 +- scripts/stop | 8 +-- scripts/update/.updateignore | 3 +- scripts/update/01-run.sh | 13 +++- services/bitcoin/citadel.yml | 18 ++++++ services/bitcoin/core.yml | 18 ++++++ services/bitcoin/knots.yml | 18 ++++++ services/{ => electrum}/electrs.yml | 4 +- services/electrum/fulcrumx-custom.yml | 19 ++++++ services/electrum/fulcrumx.yml | 19 ++++++ services/lightning/lnd.yml | 21 ++++++ services/manage.py | 64 +++++++++++-------- templates/.env-sample | 2 + templates/bitcoin-sample.conf | 4 +- templates/fulcrumx-sample.conf | 11 ++++ templates/nginx-sample.conf | 13 ++++ 25 files changed, 303 insertions(+), 107 deletions(-) create mode 100644 fulcrumx/.gitkeep create mode 100644 services/bitcoin/citadel.yml create mode 100644 services/bitcoin/core.yml create mode 100644 services/bitcoin/knots.yml rename services/{ => electrum}/electrs.yml (92%) create mode 100644 services/electrum/fulcrumx-custom.yml create mode 100644 services/electrum/fulcrumx.yml create mode 100644 services/lightning/lnd.yml create mode 100644 templates/fulcrumx-sample.conf diff --git a/.gitignore b/.gitignore index 58277bb..190b7c5 100644 --- a/.gitignore +++ b/.gitignore @@ -22,9 +22,11 @@ statuses/* app-data apps electrs/* +fulcrumx/* nginx/* redis/* events/signals/* +docker-compose.override.yml # Commit these empty directories !**/.gitkeep @@ -43,9 +45,10 @@ db/citadel-seed/* !db/.gitkeep !nginx/.gitkeep !redis/.gitkeep +!fulcrumx/.gitkeep !events/signals/.gitkeep !**/*.license services/installed.json +services/installed.yml -use-core-upstream diff --git a/app/lib/composegenerator/v1/utils/networking.py b/app/lib/composegenerator/v1/utils/networking.py index 44e612f..c24f427 100644 --- a/app/lib/composegenerator/v1/utils/networking.py +++ b/app/lib/composegenerator/v1/utils/networking.py @@ -12,8 +12,44 @@ from lib.composegenerator.v1.types import Container def getFreePort(networkingFile: str, appId: str): # Ports used currently in Citadel # TODO: Update this list, currently it's outdated - usedPorts = [80, 433, 443, 8333, 8332, 28332, 28333, 28334, 10009, 8080, 50001, 9050, 3002, 3000, 3300, 3001, 3004, 25441, - 3003, 3007, 3006, 3009, 3005, 8898, 3008, 8081, 8082, 8083, 8085, 2222, 8086, 8087, 8008, 8088, 8089, 8091] + usedPorts = [ + # Dashboard + 80, + # Sometimes used by nginx with some setups + 433, + # Dashboard SSL + 443, + # Bitcoin Core P2P + 8333, + # LND gRPC + 10009, + # LND REST + 8080, + # Electrum Server + 50001, + # Tor Proxy + 9050, + # Soon hardcoded to Specter + 25441, + 3003, + 3007, + 3006, + 3009, + 3005, + 8898, + 3008, + 8081, + 8082, + 8083, + 8085, + 2222, + 8086, + 8087, + 8008, + 8088, + 8089, + 8091 + ] networkingData = {} if os.path.isfile(networkingFile): with open(networkingFile, 'r') as f: diff --git a/app/lib/composegenerator/v2/networking.py b/app/lib/composegenerator/v2/networking.py index c0a6744..ec5d4ad 100644 --- a/app/lib/composegenerator/v2/networking.py +++ b/app/lib/composegenerator/v2/networking.py @@ -62,8 +62,9 @@ def configureMainPort(app: AppStage2, nodeRoot: str) -> AppStage3: if mainPort == False: mainPort = portDetails['port'] - mainContainer = assignIp(mainContainer, app.metadata.id, path.join( - nodeRoot, "apps", "networking.json"), path.join(nodeRoot, ".env")) + if mainContainer.network_mode != "host": + mainContainer = assignIp(mainContainer, app.metadata.id, path.join( + nodeRoot, "apps", "networking.json"), path.join(nodeRoot, ".env")) # Also set the port in metadata app.metadata.port = int(containerPort) @@ -85,6 +86,8 @@ def configureMainPort(app: AppStage2, nodeRoot: str) -> AppStage3: def configureIps(app: AppStage2, networkingFile: str, envFile: str): for container in app.containers: + if container.network_mode and container.network_mode == "host": + continue if container.noNetwork: # Check if port is defined for the container if container.port: @@ -107,6 +110,8 @@ def configureHiddenServices(app: AppStage3, nodeRoot: str) -> AppStage3: mainContainer = getMainContainer(app) for container in app.containers: + if container.network_mode and container.network_mode == "host": + continue env_var = "APP_{}_{}_IP".format( app.metadata.id.upper().replace("-", "_"), container.name.upper().replace("-", "_") diff --git a/docker-compose.yml b/docker-compose.yml index 450e78b..e2b2095 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -77,8 +77,8 @@ services: networks: default: ipv4_address: $BITCOIN_IP - lnd: - container_name: lnd + lightning: + container_name: lightning image: lightninglabs/lnd:v0.14.2-beta@sha256:8318a24a3ad7319e424253eb56efcbf38e820ebc6d6b6edeec6a8a4e3e9314a0 user: 1000:1000 depends_on: @@ -100,7 +100,7 @@ services: ipv4_address: $LND_IP dashboard: container_name: dashboard - image: ghcr.io/runcitadel/dashboard:v0.0.5@sha256:4430774d51e5731b5dc36606d7bef43f5ab2902c82cf4353ace59ebd590c2a40 + image: ghcr.io/runcitadel/dashboard:v0.0.9@sha256:d5e523e0640daca7c75084e692bb8e91a8892666d6215af0111e174b285e72b6 restart: on-failure stop_grace_period: 1m30s networks: @@ -108,10 +108,12 @@ services: ipv4_address: $DASHBOARD_IP manager: container_name: manager - image: ghcr.io/runcitadel/manager:v0.0.5@sha256:e7dc280dbeabfd4947f60676446dd69a46354f18a54e9cfb109afa98b114396c + image: ghcr.io/runcitadel/manager:v0.0.10@sha256:29b513831e8a48f9726b3b66be1a9d80e1e11acc9d384475d55adccb3c2faad3 depends_on: - tor - redis + command: + - ./start.sh restart: on-failure init: true stop_grace_period: 5m30s @@ -160,17 +162,13 @@ services: ipv4_address: $MANAGER_IP middleware: container_name: middleware - image: ghcr.io/runcitadel/middleware:v0.0.3@sha256:860fc9b1d748ac1e738322b2dc209560dc206a101be6c135bfff9b4d4fbaf023 + image: ghcr.io/runcitadel/middleware:v0.0.8@sha256:f1e400cc4544a1c2a337f4a957693b328c6ee096bff8c06f0cdfb2eabcb2f4aa depends_on: - manager - bitcoin - - lnd + - lightning - redis - command: - - ./wait-for-node-manager.sh - - $MANAGER_IP - - npm - - start + command: sh -c "./wait-for-manager.sh $MANAGER_IP && ./start.sh" restart: on-failure volumes: - ${PWD}/lnd:/lnd @@ -194,7 +192,7 @@ services: image: lncm/neutrino-switcher:1.0.5@sha256:3ddf58c5599ba22db8414f2694bfeeba086455d4a19b4955b26c3ae5e967d42a depends_on: - bitcoin - - lnd + - lightning restart: on-failure volumes: - ${PWD}/lnd:/lnd @@ -204,13 +202,13 @@ services: JSONRPCURL: http://${BITCOIN_IP}:${BITCOIN_RPC_PORT} RPCUSER: $BITCOIN_RPC_USER RPCPASS: $BITCOIN_RPC_PASS - LND_CONTAINER_NAME: lnd + LND_CONTAINER_NAME: lightning SLEEPTIME: 3600 networks: default: ipv4_address: $NEUTRINO_SWITCHER_IP - electrs: - container_name: electrs + electrum: + container_name: electrum image: ghcr.io/runcitadel/electrs:v0.9.5@sha256:5fdd76415645de14f31c43844dc143b1477f86872d2f73a041c5005d469ed510 working_dir: /data volumes: diff --git a/fulcrumx/.gitkeep b/fulcrumx/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/info.json b/info.json index 0baa821..f3ce52d 100644 --- a/info.json +++ b/info.json @@ -1,6 +1,6 @@ { - "version": "0.0.1", - "name": "Citadel 0.0.1", + "version": "0.0.2", + "name": "Citadel 0.0.2", "requires": ">=0.0.1", - "notes": "Please note: This update is not compatible with the c-lightning beta. We're resetting version numbers to 0.0.1. This update only contains one bug fix, but please install this update so you'll receive further updates." + "notes": "Please note: This update is not compatible with the c-lightning beta. This update includes a lot of bug fixes and UI improvements, and also prepares for Fulcrum integration and improves the CLI." } diff --git a/scripts/app b/scripts/app index e442fb8..fdbe27f 100755 --- a/scripts/app +++ b/scripts/app @@ -6,4 +6,21 @@ NODE_ROOT="$(dirname $(readlink -f "${BASH_SOURCE[0]}"))/.." -"${NODE_ROOT}/app/app-manager.py" "$@" +# If the first argument is stop, start, install or uninstall, and there are multiple other arguments, +# Run the "${NODE_ROOT}/app/app-manager.py" for each of the other arguments. +# Otherwise, run the "${NODE_ROOT}/app/app-manager.py" with the first argument as the command. +if [ "$1" == "stop" ] || [ "$1" == "start" ] || [ "$1" == "install" ] || [ "$1" == "uninstall" ]; then + for app in "${@:2}"; do + "${NODE_ROOT}/app/app-manager.py" "$1" "$app" + done +elif [ "$1" == "update" ]; then + for app in "${@:2}"; do + "${NODE_ROOT}/app/app-manager.py" --invoked-by-configure update "$app" + done + "${NODE_ROOT}/app/app-manager.py" generate + for app in "${@:2}"; do + "${NODE_ROOT}/app/app-manager.py" start "$app" + done +else + "${NODE_ROOT}/app/app-manager.py" "$@" +fi diff --git a/scripts/configure b/scripts/configure index caf1184..97baa78 100755 --- a/scripts/configure +++ b/scripts/configure @@ -36,7 +36,7 @@ if not is_arm64 and not is_amd64: def is_compose_rc_or_outdated(): try: output = subprocess.check_output(['docker', 'compose', 'version']) - if output.decode('utf-8').strip() != 'Docker Compose version v2.2.3': + if output.decode('utf-8').strip() != 'Docker Compose version v2.3.3': print("Using outdated docker compose, updating...") return True else: @@ -49,11 +49,15 @@ def download_docker_compose(): # Skip if os.path.expanduser('~/.docker/cli-plugins/docker-compose') exists subprocess.check_call(["mkdir", "-p", os.path.expanduser('~/.docker/cli-plugins/')]) if (os.path.exists(os.path.expanduser('~/.docker/cli-plugins/docker-compose')) or os.path.exists('/usr/lib/docker/cli-plugins/docker-compose')) and not is_compose_rc_or_outdated(): + print("Found {}\n".format(subprocess.check_output(['docker', 'compose', 'version']).decode('utf-8').strip())) return + + print("Installing docker-compose...\n") + if is_arm64: - subprocess.check_call(['wget', 'https://github.com/docker/compose/releases/download/v2.2.3/docker-compose-linux-aarch64', '-O', os.path.expanduser('~/.docker/cli-plugins/docker-compose')]) + subprocess.check_call(['wget', 'https://github.com/docker/compose/releases/download/v2.3.3/docker-compose-linux-aarch64', '-O', os.path.expanduser('~/.docker/cli-plugins/docker-compose')]) elif is_amd64: - subprocess.check_call(['wget', 'https://github.com/docker/compose/releases/download/v2.2.3/docker-compose-linux-x86_64', '-O', os.path.expanduser('~/.docker/cli-plugins/docker-compose')]) + subprocess.check_call(['wget', 'https://github.com/docker/compose/releases/download/v2.3.3/docker-compose-linux-x86_64', '-O', os.path.expanduser('~/.docker/cli-plugins/docker-compose')]) os.chmod(os.path.expanduser('~/.docker/cli-plugins/docker-compose'), 0o755) if not shutil.which("wget"): @@ -88,8 +92,7 @@ if BITCOIN_NETWORK not in ['mainnet', 'testnet', 'signet', 'regtest']: with open(os.path.join(CITADEL_ROOT, "info.json"), 'r') as file: CITADEL_VERSION=json.load(file)['version'] -print() -print("======================================") +print("\n======================================") if os.path.isfile(status_dir+'/configured'): print("=========== RECONFIGURING ============") reconfiguring=True @@ -98,12 +101,7 @@ else: reconfiguring=False print("============== CITADEL ==============") -print("======================================") -print() - -if not reconfiguring: - print("Installing electrs...") - data = subprocess.run("\"{}\" install electrs".format(os.path.join(CITADEL_ROOT, "services", "manage.py")), shell=True) +print("======================================\n") print("Installing additional services") data = subprocess.run("\"{}\" setup".format(os.path.join(CITADEL_ROOT, "services", "manage.py")), shell=True) @@ -128,18 +126,6 @@ def parse_dotenv(file_path): exit(1) return envVars -KNOTS_REINDEX_AUTO="reindex=auto" -BITCOIN_CORE_IMAGE="lncm/bitcoind:v22.0@sha256:37a1adb29b3abc9f972f0d981f45e41e5fca2e22816a023faa9fdc0084aa4507" -if os.path.isfile('../use-core-upstream') or os.path.isfile('./use-core-upstream'): - KNOTS_REINDEX_AUTO="" - # Also, open the docker-compose file and replace the image of the bitcoin service - # with the upstream version of bitcoin core - with open(os.path.join(CITADEL_ROOT, "docker-compose.yml"), 'r') as file: - docker_compose_yml = yaml.safe_load(file) - docker_compose_yml['services']['bitcoin']['image'] = BITCOIN_CORE_IMAGE - with open(os.path.join(CITADEL_ROOT, "docker-compose.yml"), 'w') as file: - yaml.dump(docker_compose_yml, file, sort_keys=False) - ########################################################## ############ Generate configuration variables ############ ########################################################## @@ -159,8 +145,7 @@ if reconfiguring: if BITCOIN_NETWORK not in ['mainnet', 'testnet', 'signet', 'regtest']: print('Error: Network must be either mainnet, testnet, signet or regtest!') exit(1) - print("Using {} network".format(BITCOIN_NETWORK)) - print() + print("Using {} network\n".format(BITCOIN_NETWORK)) BITCOIN_RPC_PORT=dotenv['BITCOIN_RPC_PORT'] BITCOIN_P2P_PORT=dotenv['BITCOIN_P2P_PORT'] BITCOIN_RPC_USER=dotenv['BITCOIN_RPC_USER'] @@ -178,16 +163,14 @@ if reconfiguring: UPDATE_CHANNEL=dotenv['UPDATE_CHANNEL'] else: # Generate RPC credentials - print("Generating auth credentials") - print() + print("Generating auth credentials\n") BITCOIN_RPC_USER="citadel" BITCOIN_RPC_DETAILS=get_data(BITCOIN_RPC_USER) BITCOIN_RPC_AUTH=BITCOIN_RPC_DETAILS['auth'] BITCOIN_RPC_PASS=BITCOIN_RPC_DETAILS['password'] # Pull Tor image and generate Tor password - print("Generating Tor password") - print() + print("Generating Tor password\n") os.system('docker pull --quiet lncm/tor:0.4.6.8') TOR_PASSWORD=get_data('itdoesntmatter')['password'] @@ -276,6 +259,7 @@ DASHBOARD_IP="10.21.21.3" MANAGER_IP="10.21.21.4" MIDDLEWARE_IP="10.21.21.5" NEUTRINO_SWITCHER_IP="10.21.21.6" +DASHBOARD_NEW_IP="10.21.21.7" BITCOIN_IP="10.21.21.8" LND_IP="10.21.21.9" ELECTRUM_IP="10.21.21.10" @@ -300,7 +284,7 @@ TOR_CONTROL_PORT="29051" DEVICE_HOSTNAME="" try: - subprocess.check_output("hostname").decode("utf-8").strip() + DEVICE_HOSTNAME=subprocess.check_output("hostname").decode("utf-8").strip() except: # The content of /etc/hostname is the device's hostname DEVICE_HOSTNAME=open("/etc/hostname").read().strip() @@ -350,11 +334,11 @@ templates_to_build = { "./templates/bitcoin-sample.conf": "./bitcoin/bitcoin.conf", "./templates/.env-sample": "./.env", "./templates/electrs-sample.toml": "./electrs/electrs.toml", + "./templates/fulcrumx-sample.conf": "./fulcrumx/fulcrumx.conf", "./templates/nginx-sample.conf": "./nginx/nginx.conf" } print("Generating configuration files...") -print() # Loop through templates_to_build and build them for template_path, output_path in templates_to_build.items(): @@ -376,26 +360,22 @@ for template_path, output_path in templates_to_build.items(): with open(output_path, 'w') as file: file.write(data) -print("Generated configuration files") -print() +print("Generated configuration files\n") -print("Installing docker-compose...") -print() +print("Checking if docker compose is installed...") download_docker_compose() + if not reconfiguring: - print("Updating apps...") - print() + print("Updating apps...\n") os.system('./scripts/app --invoked-by-configure update') elif not updating: - print("Updating apps...") - print() + print("Updating apps...\n") os.system('./scripts/app --invoked-by-configure generate') -print("Configuring permissions") -print() +print("Configuring permissions...\n") os.system('chown -R 1000:1000 {}'.format(CITADEL_ROOT)) # Touch status_dir/configured with open(status_dir+'/configured', 'w') as file: file.write('') -print("Configuration successful") +print("Configuration successful\n") print("You can now start Citadel by running:") print(" sudo ./scripts/start") diff --git a/scripts/set-update-channel b/scripts/set-update-channel index 7a2f919..a917095 100755 --- a/scripts/set-update-channel +++ b/scripts/set-update-channel @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: GPL-3.0-or-later -NODE_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/../..)" +NODE_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)" # IN ${NODE_ROOT}/.env, change the UPDATE_CHANNEL to the desired channel ($1) # If $1 is not given, fail diff --git a/scripts/start b/scripts/start index d9da226..63eff7b 100755 --- a/scripts/start +++ b/scripts/start @@ -88,6 +88,7 @@ echo ./karen &>> "${CITADEL_LOGS}/karen.log" & echo "Starting status monitors..." +echo pkill -f ./scripts/status-monitor || true ./scripts/status-monitor memory 60 &>> "${CITADEL_LOGS}/status-monitor.log" & ./scripts/status-monitor storage 60 &>> "${CITADEL_LOGS}/status-monitor.log" & @@ -103,7 +104,6 @@ echo "Starting decoy backup trigger..." echo ./scripts/backup/decoy-trigger &>> "${CITADEL_LOGS}/backup-decoy-trigger.log" & -echo echo "Resetting config files" echo ./scripts/configure diff --git a/scripts/stop b/scripts/stop index d497ec0..2d29536 100755 --- a/scripts/stop +++ b/scripts/stop @@ -32,13 +32,9 @@ export COMPOSE_HTTP_TIMEOUT=240 echo "Stopping installed apps..." echo -"${CITADEL_ROOT}/app/app-manager.py" stop installed & +"${CITADEL_ROOT}/app/app-manager.py" stop installed echo echo "Stopping Docker services..." echo -docker compose down & - -echo "Waiting for everything to finish" -wait - +docker compose down diff --git a/scripts/update/.updateignore b/scripts/update/.updateignore index 145995f..907a96e 100644 --- a/scripts/update/.updateignore +++ b/scripts/update/.updateignore @@ -9,8 +9,7 @@ events/signals logs/* app-data/* apps/networking.json -use-core-upstream nginx/* -services/installed.json +services/installed.yml apps/sourceMap.json apps/.updateignore diff --git a/scripts/update/01-run.sh b/scripts/update/01-run.sh index 383ce67..a3c5dce 100755 --- a/scripts/update/01-run.sh +++ b/scripts/update/01-run.sh @@ -28,6 +28,9 @@ IS_MIGRATING=0 # If ${CITADEL_ROOT}/c-lightning exists, fail if [[ -d "${CITADEL_ROOT}/c-lightning" ]]; then echo "This update is not compatible with the c-lightning beta." + cat < "$CITADEL_ROOT"/statuses/update-status.json +{"state": "installing", "progress": 1, "description": "This update is not compatible with c-lightning", "updateTo": "$RELEASE"} +EOF exit 1 fi @@ -97,16 +100,22 @@ docker compose pull # Stopping karen echo "Stopping background daemon" cat < "$CITADEL_ROOT"/statuses/update-status.json -{"state": "installing", "progress": 65, "description": "Stopping background daemon", "updateTo": "$RELEASE"} +{"state": "installing", "progress": 55, "description": "Stopping background daemon", "updateTo": "$RELEASE"} EOF pkill -f "\./karen" || true +echo "Stopping installed apps" +cat < "$CITADEL_ROOT"/statuses/update-status.json +{"state": "installing", "progress": 60, "description": "Stopping installed apps", "updateTo": "$RELEASE"} +EOF +cd "$CITADEL_ROOT" +./scripts/app stop installed || true + # Stop old containers echo "Stopping old containers" cat < "$CITADEL_ROOT"/statuses/update-status.json {"state": "installing", "progress": 67, "description": "Stopping old containers", "updateTo": "$RELEASE"} EOF -cd "$CITADEL_ROOT" ./scripts/stop || true diff --git a/services/bitcoin/citadel.yml b/services/bitcoin/citadel.yml new file mode 100644 index 0000000..ea2cb89 --- /dev/null +++ b/services/bitcoin/citadel.yml @@ -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 diff --git a/services/bitcoin/core.yml b/services/bitcoin/core.yml new file mode 100644 index 0000000..bec641b --- /dev/null +++ b/services/bitcoin/core.yml @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2021-2022 Citadel and contributors +# +# SPDX-License-Identifier: GPL-3.0-or-later + +bitcoin: + container_name: bitcoin + image: lncm/bitcoind:v22.0@sha256:37a1adb29b3abc9f972f0d981f45e41e5fca2e22816a023faa9fdc0084aa4507 + 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 diff --git a/services/bitcoin/knots.yml b/services/bitcoin/knots.yml new file mode 100644 index 0000000..8d32077 --- /dev/null +++ b/services/bitcoin/knots.yml @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2021-2022 Citadel and contributors +# +# SPDX-License-Identifier: GPL-3.0-or-later + +bitcoin: + container_name: bitcoin + image: nolim1t/bitcoinknots:v22.0.knots20211108@sha256:a475da2b2ecda55fcc65ea23e1a36c58b2c10549f1c3d3bb3c31c7dda1127354 + 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 \ No newline at end of file diff --git a/services/electrs.yml b/services/electrum/electrs.yml similarity index 92% rename from services/electrs.yml rename to services/electrum/electrs.yml index 824af5e..9e63309 100644 --- a/services/electrs.yml +++ b/services/electrum/electrs.yml @@ -2,8 +2,8 @@ # # SPDX-License-Identifier: GPL-3.0-or-later -electrs: - container_name: electrs +electrum: + container_name: electrum image: ghcr.io/runcitadel/electrs:v0.9.5@sha256:5fdd76415645de14f31c43844dc143b1477f86872d2f73a041c5005d469ed510 working_dir: /data volumes: diff --git a/services/electrum/fulcrumx-custom.yml b/services/electrum/fulcrumx-custom.yml new file mode 100644 index 0000000..7822423 --- /dev/null +++ b/services/electrum/fulcrumx-custom.yml @@ -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:a74abdfe8397f02482faed6bd828477c452df071129f66ad6596d0ab8d29cf39 + 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 diff --git a/services/electrum/fulcrumx.yml b/services/electrum/fulcrumx.yml new file mode 100644 index 0000000..f8ee13c --- /dev/null +++ b/services/electrum/fulcrumx.yml @@ -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 diff --git a/services/lightning/lnd.yml b/services/lightning/lnd.yml new file mode 100644 index 0000000..36c8ae3 --- /dev/null +++ b/services/lightning/lnd.yml @@ -0,0 +1,21 @@ +lightning: + container_name: lightning + image: lightninglabs/lnd:v0.14.2-beta@sha256:8318a24a3ad7319e424253eb56efcbf38e820ebc6d6b6edeec6a8a4e3e9314a0 + user: 1000:1000 + depends_on: + - tor + - bitcoin + volumes: + - ${PWD}/lnd:/data/.lnd + - ${PWD}/walletpassword:/walletpassword + environment: + HOME: /data + restart: on-failure + stop_grace_period: 5m30s + ports: + - 9735:9735 + - $LND_REST_PORT:$LND_REST_PORT + - $LND_GRPC_PORT:$LND_GRPC_PORT + networks: + default: + ipv4_address: $LND_IP \ No newline at end of file diff --git a/services/manage.py b/services/manage.py index 7c913e8..3e9a3dc 100755 --- a/services/manage.py +++ b/services/manage.py @@ -20,17 +20,19 @@ scriptDir = os.path.dirname(os.path.realpath(__file__)) nodeRoot = os.path.join(scriptDir, "..") parser = argparse.ArgumentParser(description="Manage services on your Citadel") -parser.add_argument('action', help='What to do with the service.', choices=["install", "uninstall", "setup"]) +parser.add_argument('action', help='What to do with the service.', choices=["set", "uninstall", "setup"]) parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument( - 'app', help='The service to perform an action on.', nargs='?') + 'service', help='The service to perform an action on.', nargs='?') +parser.add_argument( + 'implementation', help='The service to perform an action on.', nargs='?') args = parser.parse_args() # 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) -def installService(name): +def setService(name, implementation): # Read the YAML file - with open(os.path.join(nodeRoot, "services", name + ".yml"), 'r') as stream: + with open(os.path.join(nodeRoot, "services", name, implementation + ".yml"), 'r') as stream: service = yaml.safe_load(stream) # Read the main compose file @@ -46,18 +48,21 @@ def installService(name): # Save the service name in nodeRoot/services/installed.json, which is a JSON file with a list of installed services # If the file doesn't exist, put [] in it, then run the code below try: - with open(os.path.join(nodeRoot, "services", "installed.json"), 'r') as stream: + with open(os.path.join(nodeRoot, "services", "installed.yml"), 'r') as stream: installed = yaml.safe_load(stream) except FileNotFoundError: - installed = [] - installed.append(name) - with open(os.path.join(nodeRoot, "services", "installed.json"), 'w') as stream: - json.dump(list(set(installed)), stream, sort_keys=False) - + installed = { + "electrum": "electrs", + "lightning": "lnd", + "bitcoin": "knots" + } + installed[name] = implementation + with open(os.path.join(nodeRoot, "services", "installed.yml"), 'w') as stream: + yaml.dump(installed, stream, sort_keys=False) def uninstallService(name): # First check if a service yml definition exists to avoid uninstalling something that can't be installed or isn't supposed to be removed - if not os.path.isfile(os.path.join(nodeRoot, "services", name + ".yml")): + if not os.path.isdir(os.path.join(nodeRoot, "services", name)): print("Service definition not found, cannot uninstall") exit(1) # Read the main compose file @@ -75,33 +80,42 @@ def uninstallService(name): yaml.dump(compose, stream, sort_keys=False) # Save the service name in nodeRoot/services/installed.json, which is a JSON file with a list of installed services try: - with open(os.path.join(nodeRoot, "services", "installed.json"), 'r') as stream: + with open(os.path.join(nodeRoot, "services", "installed.yml"), 'r') as stream: installed = yaml.safe_load(stream) except FileNotFoundError: - installed = [] + installed = { + "electrum": "electrs", + "lightning": "lnd", + "bitcoin": "knots" + } try: - installed.remove(name) - except ValueError: + del installed[name] + except KeyError: pass - with open(os.path.join(nodeRoot, "services", "installed.json"), 'w') as stream: - json.dump(list(set(installed)), stream, sort_keys=False) + with open(os.path.join(nodeRoot, "services", "installed.yml"), 'w') as stream: + yaml.dump(installed, stream, sort_keys=False) # install all services from installed.json def installServices(): try: - with open(os.path.join(nodeRoot, "services", "installed.json"), 'r') as stream: - installed: List[str] = yaml.safe_load(stream) + with open(os.path.join(nodeRoot, "services", "installed.yml"), 'r') as stream: + installed = yaml.safe_load(stream) except FileNotFoundError: - installed: List[str] = [] - for service in installed: - installService(service) + installed = { + "electrum": "electrs", + "lightning": "lnd", + "bitcoin": "knots" + } + + for key, value in installed.items(): + setService(key, value) -if args.action == "install": - installService(args.app) +if args.action == "set": + setService(args.service, args.implementation) elif args.action == "uninstall": - uninstallService(args.app) + uninstallService(args.service) elif args.action == "setup": installServices() \ No newline at end of file diff --git a/templates/.env-sample b/templates/.env-sample index 34a3144..edf4480 100644 --- a/templates/.env-sample +++ b/templates/.env-sample @@ -4,12 +4,14 @@ # SPDX-License-Identifier: GPL-3.0-or-later # Citadel Core +DEVICE_HOSTNAME=.local NETWORK_IP= GATEWAY_IP= NGINX_IP= NGINX_PORT= NGINX_SSL_PORT= DASHBOARD_IP= +DASHBOARD_NEW_IP= MANAGER_IP= MIDDLEWARE_IP= NEUTRINO_SWITCHER_IP= diff --git a/templates/bitcoin-sample.conf b/templates/bitcoin-sample.conf index 956e1e1..2b99d55 100644 --- a/templates/bitcoin-sample.conf +++ b/templates/bitcoin-sample.conf @@ -35,8 +35,8 @@ blockfilterindex=1 peerbloomfilters=1 peerblockfilters=1 -# Bitcoin Knots only - +# Bitcoin Knots only, Bitcoin Core simply ignores this +reindex=auto diff --git a/templates/fulcrumx-sample.conf b/templates/fulcrumx-sample.conf new file mode 100644 index 0000000..dd5bdb3 --- /dev/null +++ b/templates/fulcrumx-sample.conf @@ -0,0 +1,11 @@ +datadir = /data +bitcoind = : +rpcuser = +rpcpassword = +tcp = 0.0.0.0:50001 +ws = 0.0.0.0:50003 +peering = false +announce = false +admin = 8000 +stats = 8080 +tor_proxy = : diff --git a/templates/nginx-sample.conf b/templates/nginx-sample.conf index f319dcd..660785e 100644 --- a/templates/nginx-sample.conf +++ b/templates/nginx-sample.conf @@ -30,6 +30,7 @@ http { proxy_pass http://:3006/; } + # dashboard (old) location / { proxy_pass http://:3004/; proxy_http_version 1.1; @@ -37,4 +38,16 @@ http { proxy_set_header Connection "upgrade"; } } + + server { + listen 8000; + + # dashboard (new) + location / { + proxy_pass http://:3010/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + } } From 53b23c557e764c3d4b001bf9ce33ce3982559cfc Mon Sep 17 00:00:00 2001 From: AaronDewes Date: Fri, 25 Mar 2022 06:42:28 +0000 Subject: [PATCH 2/3] Update dashboard --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index e2b2095..4e34f24 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -100,7 +100,7 @@ services: ipv4_address: $LND_IP dashboard: container_name: dashboard - image: ghcr.io/runcitadel/dashboard:v0.0.9@sha256:d5e523e0640daca7c75084e692bb8e91a8892666d6215af0111e174b285e72b6 + image: ghcr.io/runcitadel/dashboard:main@sha256:085bdcd7e39ff9e7786bd2277dd8040a696ad1d8be32425ec73a7728634192e4 restart: on-failure stop_grace_period: 1m30s networks: From ba951feee3dee6e7af8eb25298d5df6de59a21dd Mon Sep 17 00:00:00 2001 From: AaronDewes Date: Fri, 25 Mar 2022 06:43:20 +0000 Subject: [PATCH 3/3] Next beta --- info.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/info.json b/info.json index f3ce52d..beddf50 100644 --- a/info.json +++ b/info.json @@ -1,6 +1,6 @@ { - "version": "0.0.2", - "name": "Citadel 0.0.2", + "version": "0.0.3-beta.0", + "name": "Citadel 0.0.3 Beta 0", "requires": ">=0.0.1", - "notes": "Please note: This update is not compatible with the c-lightning beta. This update includes a lot of bug fixes and UI improvements, and also prepares for Fulcrum integration and improves the CLI." + "notes": "This update updates the beta versions to be up-to-date with the latest 0.0.2, and also adds a new dark mode toggle." }