diff --git a/README.md b/README.md index 5555776165183e..d24b11631482b3 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,62 @@ $ snap info solana $ sudo snap refresh solana --devmode ``` +### Daemon support +The snap supports running a leader or validator node as a system daemon. + +Run `sudo snap get solana` to view the current daemon configuration, and +`sudo snap logs -f solana` to view the daemon logs. + +Disable the daemon at any time by running: +```bash +$ sudo snap set solana mode= +``` + +Runtime configuration files for the daemon can be found in +`/var/snap/solana/current`. + +#### Leader daemon +```bash +$ sudo snap set solana mode=leader public-address=$(curl -s ifconfig.co) +``` + +If CUDA is available: +```bash +$ sudo snap set solana mode=leader-cuda public-address=$(curl -s ifconfig.co) +``` + +`rsync` must be configured and running on the leader. + +1. Ensure rsync is installed with `sudo apt-get -y install rsync` +2. Edit `/etc/rsyncd.conf` to include the following +``` +[solana] +path = /var/snap/solana/current +hosts allow = * +read only = true +``` +3. Run `sudo systemctl enable rsync; sudo systemctl start rsync` +4. Test by running `rsync -Pzravv rsync:///solana +solana-config` from another machine. If the leader is running on a cloud +provider it may be necessary to configure the Firewall rules to permit ingress +to port tcp:873, tcp:9900 and the port range udp:8000-udp:10000 + + +#### Validator daemon +```bash +$ sudo snap set solana mode=validator public-address=$(curl -s ifconfig.co) +``` +If CUDA is available: +```bash +$ sudo snap set solana mode=validator-cuda public-address=$(curl -s ifconfig.co) +``` + +By default the validator will connect to **testnet.solana.com**, override +the leader address by running: +```bash +$ sudo snap set solana mode=validator leader-address=127.0.0.1 #<-- change IP address +``` + Developing === diff --git a/ci/snap.sh b/ci/snap.sh index c12a9f2801dff0..8d68c77ec93574 100755 --- a/ci/snap.sh +++ b/ci/snap.sh @@ -36,5 +36,8 @@ set -x echo --- build snapcraft +source ci/upload_ci_artifact.sh +upload_ci_artifact solana_*.snap + echo --- publish $DRYRUN snapcraft push solana_*.snap --release $SNAP_CHANNEL diff --git a/ci/upload_ci_artifact.sh b/ci/upload_ci_artifact.sh new file mode 100644 index 00000000000000..9bbdce3c7369b0 --- /dev/null +++ b/ci/upload_ci_artifact.sh @@ -0,0 +1,18 @@ +# |source| me + +upload_ci_artifact() { + echo "--- artifact: $1" + if [[ -r "$1" ]]; then + ls -l "$1" + if ${BUILDKITE:-false}; then + ( + set -x + buildkite-agent artifact upload "$1" + ) + fi + else + echo ^^^ +++ + echo "$1 not found" + fi +} + diff --git a/multinode-demo/node.sh b/multinode-demo/node.sh new file mode 100755 index 00000000000000..fc3121c7aa18f7 --- /dev/null +++ b/multinode-demo/node.sh @@ -0,0 +1,141 @@ +#!/bin/bash +# +# Runs a node +# + +here="$(dirname "$0")" + +usage() { + if [[ -n "$1" ]]; then + echo "$*" + fi + + cat </dev/null 2>/dev/null + +case $MODE in +leader-cuda|leader) + echo "Starting $MODE" + set -x + # shellcheck disable=SC2086 # $PROGRAM should not be quoted + exec $PROGRAM \ + -l "$DATA_DIR/leader.json" \ + < "$DATA_DIR/genesis.log" "$DATA_DIR"/tx-*.log \ + > "$DATA_DIR"/tx-"$(date -u +%Y%m%d%H%M%S%N)".log + ;; + +validator-cuda|validator) + [[ -n "$LEADER_ADDRESS" ]] || usage "Error: leader_address not specified" + + echo "Fetching configuration from $LEADER_ADDRESS:" + ( + set -x + rm -rf "${DATA_DIR:?}/$LEADER_ADDRESS" + mkdir -p "$DATA_DIR/$LEADER_ADDRESS" + rsync -vrPz \ + "rsync://$LEADER_ADDRESS"/solana/config/ \ + "$DATA_DIR/$LEADER_ADDRESS/" + ) || exit $? + + echo "Starting $MODE, connecting to the leader at address: $LEADER_ADDRESS" + set -x + # shellcheck disable=SC2086 # $PROGRAM should not be quoted + exec $PROGRAM \ + -l "$DATA_DIR/validator.json" -t "$DATA_DIR/$LEADER_ADDRESS/leader.json" \ + < "$DATA_DIR/$LEADER_ADDRESS/genesis.log" "$DATA_DIR/$LEADER_ADDRESS"/tx-*.log + ;; + +drone) + [[ -n "$LEADER_ADDRESS" ]] || usage "Error: leader_address not specified" + + echo "Fetching configuration from $LEADER_ADDRESS:" + ( + set -x + rm -rf "${DATA_DIR:?}/$LEADER_ADDRESS" + mkdir -p "$DATA_DIR/$LEADER_ADDRESS" + rsync -vrPz \ + rsync://"$LEADER_ADDRESS"/solana/config/leader.json \ + "$DATA_DIR/$LEADER_ADDRESS/" + rsync -vrPz \ + rsync://"$LEADER_ADDRESS"/solana/config/mint-demo.json \ + "$DATA_DIR/$LEADER_ADDRESS/" + ) || exit $? + + echo "Starting $MODE, connecting to the leader at address: $LEADER_ADDRESS" + set -x + # shellcheck disable=SC2086 # $PROGRAM should not be quoted + exec $PROGRAM \ + -l "$DATA_DIR/$LEADER_ADDRESS"/leader.json \ + < "$DATA_DIR/$LEADER_ADDRESS"/mint-demo.json + ;; + + +*) + echo "Error: Unknown mode: $MODE" + exit 1 + ;; +esac + +exit 1 diff --git a/multinode-demo/setup.sh b/multinode-demo/setup.sh index 3c68abccab1159..044ebb93239d64 100755 --- a/multinode-demo/setup.sh +++ b/multinode-demo/setup.sh @@ -1,4 +1,8 @@ #!/bin/bash +# +# TODO: Merge this file with ../snap/hooks/configure +# + here=$(dirname "$0") # shellcheck source=/dev/null diff --git a/snap/hooks/configure b/snap/hooks/configure new file mode 100755 index 00000000000000..3219ee756fb764 --- /dev/null +++ b/snap/hooks/configure @@ -0,0 +1,49 @@ +#!/bin/bash -e +# +# TODO: Merge this file with ../../../multinode-demo/setup.sh +# + +if [[ -d "$SNAP" ]]; then # Running as a Linux Snap? + # Setup aliases to the normal solana command to make the reset of configure more + # readable. + shopt -s expand_aliases + export SNAP SNAP_LIBRARY_PATH + alias solana-mint-demo="$SNAP"/command-mint-demo.wrapper + alias solana-genesis-demo="$SNAP"/command-genesis-demo.wrapper + alias solana-fullnode-config="$SNAP"/command-fullnode-config.wrapper + + echo Stopping daemon + snapctl stop --disable solana.daemon-node + if [[ -z "$(snapctl get mode)" ]]; then + exit 0 + fi + + NUM_TOKENS="$(snapctl get num-tokens)" +else + NUM_TOKENS="$1" +fi + +: ${NUM_TOKENS:=1000000000} + +DATA_DIR="${SNAP_DATA:-$PWD}"/config +echo "Cleaning $DATA_DIR" + +rm -rvf "$DATA_DIR" +mkdir -p "$DATA_DIR" + +echo "Creating $DATA_DIR/mint-demo.json with $NUM_TOKENS tokens" +solana-mint-demo <<<"$NUM_TOKENS" > "$DATA_DIR"/mint-demo.json + +echo "Creating $DATA_DIR/genesis.log" +solana-genesis-demo < "$DATA_DIR"/mint-demo.json > "$DATA_DIR"/genesis.log + +echo "Creating $DATA_DIR/leader.json" +solana-fullnode-config -d > "$DATA_DIR"/leader.json + +echo "Creating $DATA_DIR/validator.json" +solana-fullnode-config -d -b 9000 > "$DATA_DIR"/validator.json + +if [[ -d "$SNAP" ]]; then + echo Starting daemon + snapctl start --enable solana.daemon-node +fi diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index fc789b6d187bab..50a51cfa1da090 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -10,6 +10,10 @@ grade: devel # CUDA dependency, so use 'devmode' confinement for now confinement: devmode +hooks: + configure: + plugs: [] + apps: drone: command: solana-drone @@ -44,7 +48,18 @@ apps: client-demo: command: solana-client-demo + daemon-node: + daemon: simple + command: node.sh + parts: + solana-scripts: + plugin: nil + override-build: | + set -x + mkdir -p $SNAPCRAFT_PART_INSTALL/bin + cp -av multinode-demo/* $SNAPCRAFT_PART_INSTALL/bin/ + solana-cuda: plugin: rust rust-channel: stable