diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..3d4481c --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,60 @@ +--- +# map of network IDs +miner_network_ids: + frontier: 1 + morden: 2 + ropsten: 3 + rinkeby: 4 + +geth_cont_image: 'ethereum/client-go:v1.8.27' +geth_cont_name: 'geth' + +geth_cont_vol: '/docker/{{ geth_cont_name }}' +geth_data_path: '{{ geth_cont_vol }}/data' +geth_keys_path: '{{ geth_cont_vol }}/keys' +geth_enode_file: '{{ geth_keys_path }}/enode' +geth_sync_check_script: '/usr/local/bin/check_geth_sync.sh' +# RPC port of administration +geth_rpc_addr: '127.0.0.1' +geth_rpc_port: 8545 +geth_rcp_api: 'eth,net,web3,personal,shh' +geth_alias: 'geth' +# Sync mode: full, fast, light +geth_sync_mode: 'light' +# Peer discovery protocol +geth_v5disc_enabled: true +# Log level: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail +geth_log_level: 3 +# 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby +geth_network_name: 'ropsten' +geth_network_id: '{{ faucet_network_ids[faucet_network_name] | mandatory }}' +# Maximum percentage of time allowed for serving LES requests (0-90) +geth_light_serv: 90 +# Maximum number of LES client peers (default: 100) +geth_light_peers: 200 +# Port to listen on +geth_port: 30303 +# Memory to use +geth_cache: 1536 +# Address to advertise +geth_public_addr: '{{ ansible_host }}' + +# security +geth_account_address: ~ +geth_account_password: ~ + +# Consul config +geth_consul_tags: + - geth + - '{{ env }}.{{ stage }}' + - '{{ geth_network_name }}' + +# resources limits to avoid killing the host +cont_mem_ratio: 0.7 +cont_mem_limit: '{{ (ansible_memtotal_mb * cont_mem_ratio|float) | int }}' +cont_swap_limit: '{{ (cont_mem_limit|int) + (ansible_swaptotal_mb * cont_mem_ratio|float) | int }}' + +# generic container beaviour +cont_state: started +cont_restart: false +cont_recreate: false diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..bd6da46 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,3 @@ +--- +- name: Save iptables rules + shell: iptables-save > /etc/iptables/rules.v4 diff --git a/tasks/consul.yml b/tasks/consul.yml new file mode 100644 index 0000000..0298801 --- /dev/null +++ b/tasks/consul.yml @@ -0,0 +1,32 @@ +--- +- name: Geth | Create sync check script + copy: + dest: '{{ geth_sync_check_script }}' + mode: 0755 + content: | + #!/usr/bin/env bash + set -e + echo -n "Geth synced: " + RESP=$(curl -s -X POST -H 'Content-type:application/json' \ + --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' \ + http://localhost:{{ faucet_geth_rpc_port }}/) + echo "${RESP}" | jq -e ".result == false" \ + || ( echo "${RESP}" | jq . ; exit 1 ) + +- name: Geth | Create Consul service definition + include_role: name=consul-service + vars: + consul_config_name: '{{ geth_cont_name | replace("-", "_") }}' + consul_services: + - name: '{{ geth_cont_name }}' + tags: '{{ geth_consul_tags }}' + port: '{{ geth_port }}' + meta: + env: '{{ env }}' + stage: '{{ stage }}' + node_addr: '{{ node_info.json.result.id }}' + node_enode: '{{ node_info.json.result.enode }}' + checks: + - id: '{{ geth_cont_name }}-rpc-status' + type: script + script: '{{ geth_sync_check_script }}' diff --git a/tasks/container.yml b/tasks/container.yml new file mode 100644 index 0000000..a178669 --- /dev/null +++ b/tasks/container.yml @@ -0,0 +1,44 @@ +--- +- name: Geth | Create the container + docker_container: + name: '{{ geth_cont_name }}' + image: '{{ geth_cont_image }}' + user: root + pull: true + restart_policy: always + state: '{{ cont_state }}' + recreate: '{{ cont_recreate }}' + restart: '{{ cont_restart }}' + # some limits due to statusd hogging resources + memory: '{{ cont_mem_limit }}m' + memory_swap: '{{ cont_swap_limit }}m' + ports: + - '{{ geth_port }}:{{ geth_port }}' + - '{{ geth_rpc_addr }}:{{ geth_rpc_port }}:{{ geth_rpc_port }}' + command: | + --networkid={{ geth_network_id }} + {% if geth_v5disc_enabled %} + --v5disc + {% endif %} + --syncmode={{ geth_sync_mode }} + {% if geth_sync_mode == 'light' %} + --lightserv={{ geth_light_serv }} + --lightpeers={{ geth_light_peers }} + {% endif %} + --verbosity={{ geth_log_level }} + --cache={{ geth_cache }} + --port={{ geth_port }} + --nat=extip:{{ geth_public_addr }} + --unlock={{ geth_account_address }} + --datadir=/data + --password=/keys/password + --keystore=/keys + --rpc + --rpcaddr=0.0.0.0 + --rpcport={{ geth_rpc_port }} + --rpcvhosts={{ faucet_geth_alias }},localhost + --rpcapi={{ geth_rcp_api }} + volumes: + - '{{ geth_cont_vol }}/keys:/keys:rw' + # WARNING: This assumes /data is mounted, see bootstrap role + - '{{ geth_data_path }}:/data:rw' diff --git a/tasks/firewall.yml b/tasks/firewall.yml new file mode 100644 index 0000000..6f624f6 --- /dev/null +++ b/tasks/firewall.yml @@ -0,0 +1,12 @@ +--- +- name: Enable LES ports + iptables: + comment: '{{ geth_name }}' + jump: ACCEPT + action: insert + chain: DOCKER-USER + source: '0.0.0.0/0' + protocol: 'tcp' + destination_port: '{{ geth_port }}' + notify: + - Save iptables rules diff --git a/tasks/generate.yml b/tasks/generate.yml new file mode 100644 index 0000000..98a5deb --- /dev/null +++ b/tasks/generate.yml @@ -0,0 +1,44 @@ +--- +- name: Geth | Create keys directory + file: + path: '{{ geth_keys_path }}' + state: directory + +- name: Geth | Find all account files + find: + paths: '{{ geth_keys_path }}' + patterns: 'UTC--*' + file_type: file + register: account_files + +- name: Geth | Set password to be empty + copy: + dest: '{{ geth_keys_path }}/password' + content: '{{ geth_account_password | mandatory }}' + +- name: Geth | Generate account + docker_container: + name: '{{ geth_cont_name }}' + image: '{{ geth_cont_image }}' + pull: true + auto_remove: yes + command: | + account new + --keystore=/keys + --password=/keys/password + volumes: + - '{{ geth_cont_vol }}/keys:/keys:rw' + when: account_files.files | length == 0 + +- name: Geth | Save account address + uri: + url: http://localhost:{{ geth_rpc_port }}/ + method: POST + body: '{"id": 1, "method": "eth_accounts"}' + body_format: json + return_content: yes + register: geth_accounts + +- name: Geth | Extract account address + set_fact: + geth_account_address: '{{ node_info.json.result | first }}' diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..363b68a --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- import_tasks: generate.yml +- import_tasks: container.yml +- import_tasks: firewall.yml +- import_tasks: save_enode.yml +- import_tasks: consul.yml diff --git a/tasks/save_enode.yml b/tasks/save_enode.yml new file mode 100644 index 0000000..1feab43 --- /dev/null +++ b/tasks/save_enode.yml @@ -0,0 +1,23 @@ +--- +- name: Geth | Wait for JSON RPC port to respond + wait_for: + host: 'localhost' + port: '{{ geth_rpc_port }}' + delay: 5 + state: drained + +- name: Geth | Get enode address + uri: + url: http://localhost:{{ geth_rpc_port }}/ + method: POST + body: '{"id": 1, "method": "admin_nodeInfo"}' + body_format: json + return_content: yes + register: node_info + +- name: 'Geth | Save enode address: {{ geth_enode_file }}' + copy: + dest: '{{ geth_enode_file }}' + content: '{{ node_info.json.result.enode }}' + owner: + mode: 0644