The previous attempt to use --ethapi as a fallback if --ens-api is not set does not work because --ens-api has a default value, and also setting --ens-api to "" is the suggested way to disable ENS lookups. Signed-off-by: Lewis Marshall <lewis@lmars.net>
		
			
				
	
	
		
			289 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			289 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/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}"
 | |
|     --ens-api      "${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 "$@"
 |