mirror of https://github.com/ethereum/go-ethereum
swarm/dev: add development environment (#14332)
This PR adds a Swarm development environment which can be run in a Docker container and provides scripts for building binaries and running Swarm clusters.pull/14567/head
parent
727eadacca
commit
0036e2a747
@ -0,0 +1,2 @@ |
|||||||
|
bin/* |
||||||
|
cluster/* |
@ -0,0 +1,2 @@ |
|||||||
|
bin/* |
||||||
|
cluster/* |
@ -0,0 +1,42 @@ |
|||||||
|
FROM ubuntu:xenial |
||||||
|
|
||||||
|
# install build + test dependencies |
||||||
|
RUN apt-get update && \ |
||||||
|
apt-get install --yes --no-install-recommends \ |
||||||
|
ca-certificates \ |
||||||
|
curl \ |
||||||
|
fuse \ |
||||||
|
g++ \ |
||||||
|
gcc \ |
||||||
|
git \ |
||||||
|
iproute2 \ |
||||||
|
iputils-ping \ |
||||||
|
less \ |
||||||
|
libc6-dev \ |
||||||
|
make \ |
||||||
|
pkg-config \ |
||||||
|
&& \ |
||||||
|
apt-get clean |
||||||
|
|
||||||
|
# install Go |
||||||
|
ENV GO_VERSION 1.8.1 |
||||||
|
RUN curl -fSLo golang.tar.gz "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" && \ |
||||||
|
tar -xzf golang.tar.gz -C /usr/local && \ |
||||||
|
rm golang.tar.gz |
||||||
|
ENV GOPATH /go |
||||||
|
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH |
||||||
|
|
||||||
|
# install docker CLI |
||||||
|
RUN curl -fSLo docker.tar.gz https://get.docker.com/builds/Linux/x86_64/docker-17.04.0-ce.tgz && \ |
||||||
|
tar -xzf docker.tar.gz -C /usr/local/bin --strip-components=1 docker/docker && \ |
||||||
|
rm docker.tar.gz |
||||||
|
|
||||||
|
# install jq |
||||||
|
RUN curl -fSLo /usr/local/bin/jq https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 && \ |
||||||
|
chmod +x /usr/local/bin/jq |
||||||
|
|
||||||
|
# install govendor |
||||||
|
RUN go get -u github.com/kardianos/govendor |
||||||
|
|
||||||
|
# add custom bashrc |
||||||
|
ADD bashrc /root/.bashrc |
@ -0,0 +1,14 @@ |
|||||||
|
.PHONY: build cluster test |
||||||
|
|
||||||
|
default: build |
||||||
|
|
||||||
|
build: |
||||||
|
go build -o bin/swarm github.com/ethereum/go-ethereum/cmd/swarm
|
||||||
|
go build -o bin/geth github.com/ethereum/go-ethereum/cmd/geth
|
||||||
|
go build -o bin/bootnode github.com/ethereum/go-ethereum/cmd/bootnode
|
||||||
|
|
||||||
|
cluster: build |
||||||
|
scripts/boot-cluster.sh
|
||||||
|
|
||||||
|
test: |
||||||
|
go test -v github.com/ethereum/go-ethereum/swarm/...
|
@ -0,0 +1,20 @@ |
|||||||
|
Swarm development environment |
||||||
|
============================= |
||||||
|
|
||||||
|
The Swarm development environment is a Linux bash shell which can be run in a |
||||||
|
Docker container and provides a predictable build and test environment. |
||||||
|
|
||||||
|
### Start the Docker container |
||||||
|
|
||||||
|
Run the `run.sh` script to build the Docker image and run it, you will then be |
||||||
|
at a bash prompt inside the `swarm/dev` directory. |
||||||
|
|
||||||
|
### Build binaries |
||||||
|
|
||||||
|
Run `make` to build the `swarm`, `geth` and `bootnode` binaries into the |
||||||
|
`swarm/dev/bin` directory. |
||||||
|
|
||||||
|
### Boot a cluster |
||||||
|
|
||||||
|
Run `make cluster` to start a 3 node Swarm cluster, or run |
||||||
|
`scripts/boot-cluster.sh --size N` to boot a cluster of size N. |
@ -0,0 +1,21 @@ |
|||||||
|
export ROOT="${GOPATH}/src/github.com/ethereum/go-ethereum" |
||||||
|
export PATH="${ROOT}/swarm/dev/bin:${PATH}" |
||||||
|
|
||||||
|
cd "${ROOT}/swarm/dev" |
||||||
|
|
||||||
|
cat <<WELCOME |
||||||
|
|
||||||
|
============================================= |
||||||
|
|
||||||
|
Welcome to the swarm development environment. |
||||||
|
|
||||||
|
- Run 'make' to build the swarm, geth and bootnode binaries |
||||||
|
- Run 'make test' to run the swarm unit tests |
||||||
|
- Run 'make cluster' to start a swarm cluster |
||||||
|
- Run 'exit' to exit the development environment |
||||||
|
|
||||||
|
See the 'scripts' directory for some useful scripts. |
||||||
|
|
||||||
|
============================================= |
||||||
|
|
||||||
|
WELCOME |
@ -0,0 +1,90 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
# |
||||||
|
# A script to build and run the Swarm development environment using Docker. |
||||||
|
|
||||||
|
set -e |
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)" |
||||||
|
|
||||||
|
# DEFAULT_NAME is the default name for the Docker image and container |
||||||
|
DEFAULT_NAME="swarm-dev" |
||||||
|
|
||||||
|
usage() { |
||||||
|
cat >&2 <<USAGE |
||||||
|
usage: $0 [options] |
||||||
|
|
||||||
|
Build and run the Swarm development environment. |
||||||
|
|
||||||
|
Depends on Docker being installed locally. |
||||||
|
|
||||||
|
OPTIONS: |
||||||
|
-n, --name NAME Docker image and container name [default: ${DEFAULT_NAME}] |
||||||
|
-d, --docker-args ARGS Custom args to pass to 'docker run' (e.g. '-p 8000:8000' to expose a port) |
||||||
|
-h, --help Show this message |
||||||
|
USAGE |
||||||
|
} |
||||||
|
|
||||||
|
main() { |
||||||
|
local name="${DEFAULT_NAME}" |
||||||
|
local docker_args="" |
||||||
|
parse_args "$@" |
||||||
|
build_image |
||||||
|
run_image |
||||||
|
} |
||||||
|
|
||||||
|
parse_args() { |
||||||
|
while true; do |
||||||
|
case "$1" in |
||||||
|
-h | --help) |
||||||
|
usage |
||||||
|
exit 0 |
||||||
|
;; |
||||||
|
-n | --name) |
||||||
|
if [[ -z "$2" ]]; then |
||||||
|
echo "ERROR: --name flag requires an argument" >&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
name="$2" |
||||||
|
shift 2 |
||||||
|
;; |
||||||
|
-d | --docker-args) |
||||||
|
if [[ -z "$2" ]]; then |
||||||
|
echo "ERROR: --docker-args flag requires an argument" >&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
docker_args="$2" |
||||||
|
shift 2 |
||||||
|
;; |
||||||
|
*) |
||||||
|
break |
||||||
|
;; |
||||||
|
esac |
||||||
|
done |
||||||
|
|
||||||
|
if [[ $# -ne 0 ]]; then |
||||||
|
usage |
||||||
|
echo "ERROR: invalid arguments" >&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
build_image() { |
||||||
|
docker build --tag "${name}" "${ROOT}/swarm/dev" |
||||||
|
} |
||||||
|
|
||||||
|
run_image() { |
||||||
|
exec docker run \ |
||||||
|
--privileged \ |
||||||
|
--interactive \ |
||||||
|
--tty \ |
||||||
|
--rm \ |
||||||
|
--hostname "${name}" \ |
||||||
|
--name "${name}" \ |
||||||
|
--volume "${ROOT}:/go/src/github.com/ethereum/go-ethereum" \ |
||||||
|
--volume "/var/run/docker.sock:/var/run/docker.sock" \ |
||||||
|
${docker_args} \ |
||||||
|
"${name}" \ |
||||||
|
/bin/bash |
||||||
|
} |
||||||
|
|
||||||
|
main "$@" |
@ -0,0 +1,288 @@ |
|||||||
|
#!/bin/bash |
||||||
|
# |
||||||
|
# A script to boot a dev swarm cluster on a Linux host (typically in a Docker |
||||||
|
# container started with swarm/dev/run.sh). |
||||||
|
# |
||||||
|
# The cluster contains a bootnode, a geth node and multiple swarm nodes, with |
||||||
|
# each node having its own data directory in a base directory passed with the |
||||||
|
# --dir flag (default is swarm/dev/cluster). |
||||||
|
# |
||||||
|
# To avoid using different ports for each node and to make networking more |
||||||
|
# realistic, each node gets its own network namespace with IPs assigned from |
||||||
|
# the 192.168.33.0/24 subnet: |
||||||
|
# |
||||||
|
# bootnode: 192.168.33.2 |
||||||
|
# geth: 192.168.33.3 |
||||||
|
# swarm: 192.168.33.10{1,2,...,n} |
||||||
|
|
||||||
|
set -e |
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" |
||||||
|
source "${ROOT}/swarm/dev/scripts/util.sh" |
||||||
|
|
||||||
|
# DEFAULT_BASE_DIR is the default base directory to store node data |
||||||
|
DEFAULT_BASE_DIR="${ROOT}/swarm/dev/cluster" |
||||||
|
|
||||||
|
# DEFAULT_CLUSTER_SIZE is the default swarm cluster size |
||||||
|
DEFAULT_CLUSTER_SIZE=3 |
||||||
|
|
||||||
|
# Linux bridge configuration for connecting the node network namespaces |
||||||
|
BRIDGE_NAME="swarmbr0" |
||||||
|
BRIDGE_IP="192.168.33.1" |
||||||
|
|
||||||
|
# static bootnode configuration |
||||||
|
BOOTNODE_IP="192.168.33.2" |
||||||
|
BOOTNODE_PORT="30301" |
||||||
|
BOOTNODE_KEY="32078f313bea771848db70745225c52c00981589ad6b5b49163f0f5ee852617d" |
||||||
|
BOOTNODE_PUBKEY="760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1b01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d" |
||||||
|
BOOTNODE_URL="enode://${BOOTNODE_PUBKEY}@${BOOTNODE_IP}:${BOOTNODE_PORT}" |
||||||
|
|
||||||
|
# static geth configuration |
||||||
|
GETH_IP="192.168.33.3" |
||||||
|
GETH_RPC_PORT="8545" |
||||||
|
GETH_RPC_URL="http://${GETH_IP}:${GETH_RPC_PORT}" |
||||||
|
|
||||||
|
usage() { |
||||||
|
cat >&2 <<USAGE |
||||||
|
usage: $0 [options] |
||||||
|
|
||||||
|
Boot a dev swarm cluster. |
||||||
|
|
||||||
|
OPTIONS: |
||||||
|
-d, --dir DIR Base directory to store node data [default: ${DEFAULT_BASE_DIR}] |
||||||
|
-s, --size SIZE Size of swarm cluster [default: ${DEFAULT_CLUSTER_SIZE}] |
||||||
|
-h, --help Show this message |
||||||
|
USAGE |
||||||
|
} |
||||||
|
|
||||||
|
main() { |
||||||
|
local base_dir="${DEFAULT_BASE_DIR}" |
||||||
|
local cluster_size="${DEFAULT_CLUSTER_SIZE}" |
||||||
|
|
||||||
|
parse_args "$@" |
||||||
|
|
||||||
|
local pid_dir="${base_dir}/pids" |
||||||
|
local log_dir="${base_dir}/logs" |
||||||
|
mkdir -p "${base_dir}" "${pid_dir}" "${log_dir}" |
||||||
|
|
||||||
|
stop_cluster |
||||||
|
create_network |
||||||
|
start_bootnode |
||||||
|
start_geth_node |
||||||
|
start_swarm_nodes |
||||||
|
} |
||||||
|
|
||||||
|
parse_args() { |
||||||
|
while true; do |
||||||
|
case "$1" in |
||||||
|
-h | --help) |
||||||
|
usage |
||||||
|
exit 0 |
||||||
|
;; |
||||||
|
-d | --dir) |
||||||
|
if [[ -z "$2" ]]; then |
||||||
|
fail "--dir flag requires an argument" |
||||||
|
fi |
||||||
|
base_dir="$2" |
||||||
|
shift 2 |
||||||
|
;; |
||||||
|
-s | --size) |
||||||
|
if [[ -z "$2" ]]; then |
||||||
|
fail "--size flag requires an argument" |
||||||
|
fi |
||||||
|
cluster_size="$2" |
||||||
|
shift 2 |
||||||
|
;; |
||||||
|
*) |
||||||
|
break |
||||||
|
;; |
||||||
|
esac |
||||||
|
done |
||||||
|
|
||||||
|
if [[ $# -ne 0 ]]; then |
||||||
|
usage |
||||||
|
fail "ERROR: invalid arguments: $@" |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
stop_cluster() { |
||||||
|
info "stopping existing cluster" |
||||||
|
"${ROOT}/swarm/dev/scripts/stop-cluster.sh" --dir "${base_dir}" |
||||||
|
} |
||||||
|
|
||||||
|
# create_network creates a Linux bridge which is used to connect the node |
||||||
|
# network namespaces together |
||||||
|
create_network() { |
||||||
|
local subnet="${BRIDGE_IP}/24" |
||||||
|
|
||||||
|
info "creating ${subnet} network on ${BRIDGE_NAME}" |
||||||
|
ip link add name "${BRIDGE_NAME}" type bridge |
||||||
|
ip link set dev "${BRIDGE_NAME}" up |
||||||
|
ip address add "${subnet}" dev "${BRIDGE_NAME}" |
||||||
|
} |
||||||
|
|
||||||
|
# start_bootnode starts a bootnode which is used to bootstrap the geth and |
||||||
|
# swarm nodes |
||||||
|
start_bootnode() { |
||||||
|
local key_file="${base_dir}/bootnode.key" |
||||||
|
echo -n "${BOOTNODE_KEY}" > "${key_file}" |
||||||
|
|
||||||
|
local args=( |
||||||
|
--addr "${BOOTNODE_IP}:${BOOTNODE_PORT}" |
||||||
|
--nodekey "${key_file}" |
||||||
|
--verbosity "6" |
||||||
|
) |
||||||
|
|
||||||
|
start_node "bootnode" "${BOOTNODE_IP}" "$(which bootnode)" ${args[@]} |
||||||
|
} |
||||||
|
|
||||||
|
# start_geth_node starts a geth node with --datadir pointing at <base-dir>/geth |
||||||
|
# and a single, unlocked account with password "geth" |
||||||
|
start_geth_node() { |
||||||
|
local dir="${base_dir}/geth" |
||||||
|
mkdir -p "${dir}" |
||||||
|
|
||||||
|
local password="geth" |
||||||
|
echo "${password}" > "${dir}/password" |
||||||
|
|
||||||
|
# create an account if necessary |
||||||
|
if [[ ! -e "${dir}/keystore" ]]; then |
||||||
|
info "creating geth account" |
||||||
|
create_account "${dir}" "${password}" |
||||||
|
fi |
||||||
|
|
||||||
|
# get the account address |
||||||
|
local address="$(jq --raw-output '.address' ${dir}/keystore/*)" |
||||||
|
if [[ -z "${address}" ]]; then |
||||||
|
fail "failed to get geth account address" |
||||||
|
fi |
||||||
|
|
||||||
|
local args=( |
||||||
|
--datadir "${dir}" |
||||||
|
--networkid "321" |
||||||
|
--bootnodes "${BOOTNODE_URL}" |
||||||
|
--unlock "${address}" |
||||||
|
--password "${dir}/password" |
||||||
|
--rpc |
||||||
|
--rpcaddr "${GETH_IP}" |
||||||
|
--rpcport "${GETH_RPC_PORT}" |
||||||
|
--verbosity "6" |
||||||
|
) |
||||||
|
|
||||||
|
start_node "geth" "${GETH_IP}" "$(which geth)" ${args[@]} |
||||||
|
} |
||||||
|
|
||||||
|
start_swarm_nodes() { |
||||||
|
for i in $(seq 1 ${cluster_size}); do |
||||||
|
start_swarm_node "${i}" |
||||||
|
done |
||||||
|
} |
||||||
|
|
||||||
|
# start_swarm_node starts a swarm node with a name like "swarmNN" (where NN is |
||||||
|
# a zero-padded integer like "07"), --datadir pointing at <base-dir>/<name> |
||||||
|
# (e.g. <base-dir>/swarm07) and a single account with <name> as the password |
||||||
|
start_swarm_node() { |
||||||
|
local num=$1 |
||||||
|
local name="swarm$(printf '%02d' ${num})" |
||||||
|
local ip="192.168.33.1$(printf '%02d' ${num})" |
||||||
|
|
||||||
|
local dir="${base_dir}/${name}" |
||||||
|
mkdir -p "${dir}" |
||||||
|
|
||||||
|
local password="${name}" |
||||||
|
echo "${password}" > "${dir}/password" |
||||||
|
|
||||||
|
# create an account if necessary |
||||||
|
if [[ ! -e "${dir}/keystore" ]]; then |
||||||
|
info "creating account for ${name}" |
||||||
|
create_account "${dir}" "${password}" |
||||||
|
fi |
||||||
|
|
||||||
|
# get the account address |
||||||
|
local address="$(jq --raw-output '.address' ${dir}/keystore/*)" |
||||||
|
if [[ -z "${address}" ]]; then |
||||||
|
fail "failed to get swarm account address" |
||||||
|
fi |
||||||
|
|
||||||
|
local args=( |
||||||
|
--bootnodes "${BOOTNODE_URL}" |
||||||
|
--datadir "${dir}" |
||||||
|
--identity "${name}" |
||||||
|
--ethapi "${GETH_RPC_URL}" |
||||||
|
--bzznetworkid "321" |
||||||
|
--bzzaccount "${address}" |
||||||
|
--password "${dir}/password" |
||||||
|
--verbosity "6" |
||||||
|
) |
||||||
|
|
||||||
|
start_node "${name}" "${ip}" "$(which swarm)" ${args[@]} |
||||||
|
} |
||||||
|
|
||||||
|
# start_node runs the node command as a daemon in a network namespace |
||||||
|
start_node() { |
||||||
|
local name="$1" |
||||||
|
local ip="$2" |
||||||
|
local path="$3" |
||||||
|
local cmd_args=${@:4} |
||||||
|
|
||||||
|
info "starting ${name} with IP ${ip}" |
||||||
|
|
||||||
|
create_node_network "${name}" "${ip}" |
||||||
|
|
||||||
|
# add a marker to the log file |
||||||
|
cat >> "${log_dir}/${name}.log" <<EOF |
||||||
|
|
||||||
|
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
||||||
|
Starting ${name} node - $(date) |
||||||
|
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
||||||
|
|
||||||
|
EOF |
||||||
|
|
||||||
|
# run the command in the network namespace using start-stop-daemon to |
||||||
|
# daemonise the process, sending all output to the log file |
||||||
|
local daemon_args=( |
||||||
|
--start |
||||||
|
--background |
||||||
|
--no-close |
||||||
|
--make-pidfile |
||||||
|
--pidfile "${pid_dir}/${name}.pid" |
||||||
|
--exec "${path}" |
||||||
|
) |
||||||
|
if ! ip netns exec "${name}" start-stop-daemon ${daemon_args[@]} -- $cmd_args &>> "${log_dir}/${name}.log"; then |
||||||
|
fail "could not start ${name}, check ${log_dir}/${name}.log" |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
# create_node_network creates a network namespace and connects it to the Linux |
||||||
|
# bridge using a veth pair |
||||||
|
create_node_network() { |
||||||
|
local name="$1" |
||||||
|
local ip="$2" |
||||||
|
|
||||||
|
# create the namespace |
||||||
|
ip netns add "${name}" |
||||||
|
|
||||||
|
# create the veth pair |
||||||
|
local veth0="veth${name}0" |
||||||
|
local veth1="veth${name}1" |
||||||
|
ip link add name "${veth0}" type veth peer name "${veth1}" |
||||||
|
|
||||||
|
# add one end to the bridge |
||||||
|
ip link set dev "${veth0}" master "${BRIDGE_NAME}" |
||||||
|
ip link set dev "${veth0}" up |
||||||
|
|
||||||
|
# add the other end to the namespace, rename it eth0 and give it the ip |
||||||
|
ip link set dev "${veth1}" netns "${name}" |
||||||
|
ip netns exec "${name}" ip link set dev "${veth1}" name "eth0" |
||||||
|
ip netns exec "${name}" ip link set dev "eth0" up |
||||||
|
ip netns exec "${name}" ip address add "${ip}/24" dev "eth0" |
||||||
|
} |
||||||
|
|
||||||
|
create_account() { |
||||||
|
local dir=$1 |
||||||
|
local password=$2 |
||||||
|
|
||||||
|
geth --datadir "${dir}" --password /dev/stdin account new <<< "${password}" |
||||||
|
} |
||||||
|
|
||||||
|
main "$@" |
@ -0,0 +1,96 @@ |
|||||||
|
#!/bin/bash |
||||||
|
# |
||||||
|
# A script to upload random data to a swarm cluster. |
||||||
|
# |
||||||
|
# Example: |
||||||
|
# |
||||||
|
# random-uploads.sh --addr 192.168.33.101:8500 --size 40k --count 1000 |
||||||
|
|
||||||
|
set -e |
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" |
||||||
|
source "${ROOT}/swarm/dev/scripts/util.sh" |
||||||
|
|
||||||
|
DEFAULT_ADDR="localhost:8500" |
||||||
|
DEFAULT_UPLOAD_SIZE="40k" |
||||||
|
DEFAULT_UPLOAD_COUNT="1000" |
||||||
|
|
||||||
|
usage() { |
||||||
|
cat >&2 <<USAGE |
||||||
|
usage: $0 [options] |
||||||
|
|
||||||
|
Upload random data to a Swarm cluster. |
||||||
|
|
||||||
|
OPTIONS: |
||||||
|
-a, --addr ADDR Swarm API address [default: ${DEFAULT_ADDR}] |
||||||
|
-s, --size SIZE Individual upload size [default: ${DEFAULT_UPLOAD_SIZE}] |
||||||
|
-c, --count COUNT Number of uploads [default: ${DEFAULT_UPLOAD_COUNT}] |
||||||
|
-h, --help Show this message |
||||||
|
USAGE |
||||||
|
} |
||||||
|
|
||||||
|
main() { |
||||||
|
local addr="${DEFAULT_ADDR}" |
||||||
|
local upload_size="${DEFAULT_UPLOAD_SIZE}" |
||||||
|
local upload_count="${DEFAULT_UPLOAD_COUNT}" |
||||||
|
|
||||||
|
parse_args "$@" |
||||||
|
|
||||||
|
info "uploading ${upload_count} ${upload_size} random files to ${addr}" |
||||||
|
|
||||||
|
for i in $(seq 1 ${upload_count}); do |
||||||
|
info "upload ${i} / ${upload_count}:" |
||||||
|
do_random_upload |
||||||
|
echo |
||||||
|
done |
||||||
|
} |
||||||
|
|
||||||
|
do_random_upload() { |
||||||
|
curl -fsSL -X POST --data-binary "$(random_data)" "http://${addr}/bzzr:/" |
||||||
|
} |
||||||
|
|
||||||
|
random_data() { |
||||||
|
dd if=/dev/urandom of=/dev/stdout bs="${upload_size}" count=1 2>/dev/null |
||||||
|
} |
||||||
|
|
||||||
|
parse_args() { |
||||||
|
while true; do |
||||||
|
case "$1" in |
||||||
|
-h | --help) |
||||||
|
usage |
||||||
|
exit 0 |
||||||
|
;; |
||||||
|
-a | --addr) |
||||||
|
if [[ -z "$2" ]]; then |
||||||
|
fail "--addr flag requires an argument" |
||||||
|
fi |
||||||
|
addr="$2" |
||||||
|
shift 2 |
||||||
|
;; |
||||||
|
-s | --size) |
||||||
|
if [[ -z "$2" ]]; then |
||||||
|
fail "--size flag requires an argument" |
||||||
|
fi |
||||||
|
upload_size="$2" |
||||||
|
shift 2 |
||||||
|
;; |
||||||
|
-c | --count) |
||||||
|
if [[ -z "$2" ]]; then |
||||||
|
fail "--count flag requires an argument" |
||||||
|
fi |
||||||
|
upload_count="$2" |
||||||
|
shift 2 |
||||||
|
;; |
||||||
|
*) |
||||||
|
break |
||||||
|
;; |
||||||
|
esac |
||||||
|
done |
||||||
|
|
||||||
|
if [[ $# -ne 0 ]]; then |
||||||
|
usage |
||||||
|
fail "ERROR: invalid arguments: $@" |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
main "$@" |
@ -0,0 +1,98 @@ |
|||||||
|
#!/bin/bash |
||||||
|
# |
||||||
|
# A script to shutdown a dev swarm cluster. |
||||||
|
|
||||||
|
set -e |
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" |
||||||
|
source "${ROOT}/swarm/dev/scripts/util.sh" |
||||||
|
|
||||||
|
DEFAULT_BASE_DIR="${ROOT}/swarm/dev/cluster" |
||||||
|
|
||||||
|
usage() { |
||||||
|
cat >&2 <<USAGE |
||||||
|
usage: $0 [options] |
||||||
|
|
||||||
|
Shutdown a dev swarm cluster. |
||||||
|
|
||||||
|
OPTIONS: |
||||||
|
-d, --dir DIR Base directory [default: ${DEFAULT_BASE_DIR}] |
||||||
|
-h, --help Show this message |
||||||
|
USAGE |
||||||
|
} |
||||||
|
|
||||||
|
main() { |
||||||
|
local base_dir="${DEFAULT_BASE_DIR}" |
||||||
|
|
||||||
|
parse_args "$@" |
||||||
|
|
||||||
|
local pid_dir="${base_dir}/pids" |
||||||
|
|
||||||
|
stop_swarm_nodes |
||||||
|
stop_node "geth" |
||||||
|
stop_node "bootnode" |
||||||
|
delete_network |
||||||
|
} |
||||||
|
|
||||||
|
parse_args() { |
||||||
|
while true; do |
||||||
|
case "$1" in |
||||||
|
-h | --help) |
||||||
|
usage |
||||||
|
exit 0 |
||||||
|
;; |
||||||
|
-d | --dir) |
||||||
|
if [[ -z "$2" ]]; then |
||||||
|
fail "--dir flag requires an argument" |
||||||
|
fi |
||||||
|
base_dir="$2" |
||||||
|
shift 2 |
||||||
|
;; |
||||||
|
*) |
||||||
|
break |
||||||
|
;; |
||||||
|
esac |
||||||
|
done |
||||||
|
|
||||||
|
if [[ $# -ne 0 ]]; then |
||||||
|
usage |
||||||
|
fail "ERROR: invalid arguments: $@" |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
stop_swarm_nodes() { |
||||||
|
for name in $(ls "${pid_dir}" | grep -oP 'swarm\d+'); do |
||||||
|
stop_node "${name}" |
||||||
|
done |
||||||
|
} |
||||||
|
|
||||||
|
stop_node() { |
||||||
|
local name=$1 |
||||||
|
local pid_file="${pid_dir}/${name}.pid" |
||||||
|
|
||||||
|
if [[ -e "${pid_file}" ]]; then |
||||||
|
info "stopping ${name}" |
||||||
|
start-stop-daemon \ |
||||||
|
--stop \ |
||||||
|
--pidfile "${pid_file}" \ |
||||||
|
--remove-pidfile \ |
||||||
|
--oknodo \ |
||||||
|
--retry 15 |
||||||
|
fi |
||||||
|
|
||||||
|
if ip netns list | grep -qF "${name}"; then |
||||||
|
ip netns delete "${name}" |
||||||
|
fi |
||||||
|
|
||||||
|
if ip link show "veth${name}0" &>/dev/null; then |
||||||
|
ip link delete dev "veth${name}0" |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
delete_network() { |
||||||
|
if ip link show "swarmbr0" &>/dev/null; then |
||||||
|
ip link delete dev "swarmbr0" |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
main "$@" |
@ -0,0 +1,53 @@ |
|||||||
|
# shared shell functions |
||||||
|
|
||||||
|
info() { |
||||||
|
local msg="$@" |
||||||
|
local timestamp="$(date +%H:%M:%S)" |
||||||
|
say "===> ${timestamp} ${msg}" "green" |
||||||
|
} |
||||||
|
|
||||||
|
warn() { |
||||||
|
local msg="$@" |
||||||
|
local timestamp=$(date +%H:%M:%S) |
||||||
|
say "===> ${timestamp} WARN: ${msg}" "yellow" >&2 |
||||||
|
} |
||||||
|
|
||||||
|
fail() { |
||||||
|
local msg="$@" |
||||||
|
say "ERROR: ${msg}" "red" >&2 |
||||||
|
exit 1 |
||||||
|
} |
||||||
|
|
||||||
|
# say prints the given message to STDOUT, using the optional color if |
||||||
|
# STDOUT is a terminal. |
||||||
|
# |
||||||
|
# usage: |
||||||
|
# |
||||||
|
# say "foo" - prints "foo" |
||||||
|
# say "bar" "red" - prints "bar" in red |
||||||
|
# say "baz" "green" - prints "baz" in green |
||||||
|
# say "qux" "red" | tee - prints "qux" with no colour |
||||||
|
# |
||||||
|
say() { |
||||||
|
local msg=$1 |
||||||
|
local color=$2 |
||||||
|
|
||||||
|
if [[ -n "${color}" ]] && [[ -t 1 ]]; then |
||||||
|
case "${color}" in |
||||||
|
red) |
||||||
|
echo -e "\033[1;31m${msg}\033[0m" |
||||||
|
;; |
||||||
|
green) |
||||||
|
echo -e "\033[1;32m${msg}\033[0m" |
||||||
|
;; |
||||||
|
yellow) |
||||||
|
echo -e "\033[1;33m${msg}\033[0m" |
||||||
|
;; |
||||||
|
*) |
||||||
|
echo "${msg}" |
||||||
|
;; |
||||||
|
esac |
||||||
|
else |
||||||
|
echo "${msg}" |
||||||
|
fi |
||||||
|
} |
Loading…
Reference in new issue