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.
This commit is contained in:
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