From 1e38f1d19f7b7e1ef9b328e71cb1c4ef51bfc6c5 Mon Sep 17 00:00:00 2001 From: Chris Gianelloni Date: Sun, 22 Sep 2024 13:21:57 -0400 Subject: [PATCH] feat: role for our go node Signed-off-by: Chris Gianelloni --- roles/go_node/README.md | 51 +++++++++++ roles/go_node/defaults/main.yml | 85 +++++++++++++++++++ roles/go_node/meta/main.yml | 3 + roles/go_node/tasks/docker.yml | 54 ++++++++++++ roles/go_node/tasks/main.yml | 50 +++++++++++ .../go_node/templates/custom-topology.json.j2 | 56 ++++++++++++ 6 files changed, 299 insertions(+) create mode 100644 roles/go_node/README.md create mode 100644 roles/go_node/defaults/main.yml create mode 100644 roles/go_node/meta/main.yml create mode 100644 roles/go_node/tasks/docker.yml create mode 100644 roles/go_node/tasks/main.yml create mode 100644 roles/go_node/templates/custom-topology.json.j2 diff --git a/roles/go_node/README.md b/roles/go_node/README.md new file mode 100644 index 0000000..dfc4b63 --- /dev/null +++ b/roles/go_node/README.md @@ -0,0 +1,51 @@ +go_node +========= + +This role deploys a Blink Labs Go Cardano node instance. + +Requirements +------------ + +Any pre-requisites that may not be covered by Ansible itself or the role should +be mentioned here. For instance, if the role uses the EC2 module, it may be a +good idea to mention in this section that the boto package is required. + +Role Variables +-------------- + +A description of the settable variables for this role should go here, including +any variables that are in defaults/main.yml, vars/main.yml, and any variables +that can/should be set via parameters to the role. Any variables that are read +from other roles and/or the global scope (ie. hostvars, group vars, etc.) +should be mentioned here as well. + +Dependencies +------------ + +A list of other roles hosted on Galaxy should go here, plus any details in +regards to parameters that may need to be set for other roles, or variables +that are used from other roles. + +Example Playbook +---------------- + +Including an example of how to use your role (for instance, with variables +passed in as parameters) is always nice for users too: + +```yaml + - hosts: servers + tasks: + - include_role: + name: blinklabs.cardano.go_node +``` + +License +------- + +Apache 2.0 + +Author Information +------------------ + +An optional section for the role authors to include contact information, or a +website (HTML is not allowed). diff --git a/roles/go_node/defaults/main.yml b/roles/go_node/defaults/main.yml new file mode 100644 index 0000000..384917b --- /dev/null +++ b/roles/go_node/defaults/main.yml @@ -0,0 +1,85 @@ +--- +# Install method +go_node_install_method: 'docker' + +# Cardano node version +go_node_version: 'main' + +# Cardano network +go_node_network: mainnet + +# Base host directory for node data +go_node_dir: /opt/cardano + +# Config directory for host/container +go_node_config_dir: '{{ go_node_dir }}/config' +go_node_config_container_dir: '{{ go_node_config_dir }}' + +# DB directory for host/container +go_node_db_dir: '{{ go_node_dir }}/data' +go_node_db_container_dir: '{{ go_node_db_dir }}' + +# IPC directory for host/container +go_node_ipc_dir: '{{ go_node_dir }}/ipc' +go_node_ipc_container_dir: '{{ go_node_ipc_dir }}' + +# Topology directory for host/container +go_node_topology_dir: '{{ go_node_config_dir }}' +go_node_topology_container_dir: '{{ go_node_topology_dir }}' + +# Block producer keys directory for host/container +go_node_keys_dir: '{{ go_node_config_dir }}/keys' +go_node_keys_container_dir: '{{ go_node_keys_dir }}' + +# User/group for file/directory ownership +go_node_user: root +go_node_group: root + +# Docker image +go_node_docker_image: 'ghcr.io/blinklabs-io/node:{{ go_node_version }}' + +# Docker container name +go_node_docker_container_name: node + +# Port for host/container +go_node_container_port: 3001 +go_node_port: '{{ go_node_container_port }}' + +# Metrics port for host/container +go_node_metrics_container_port: 12798 +go_node_metrics_port: '{{ go_node_metrics_container_port }}' + +# Socket file name +go_node_socket_name: node.socket + +# Config +go_node_manage_config: false # this currently controls mounting only +go_node_config_file: '{{ go_node_config_container_dir }}/{{ go_node_network }}/config.json' + +# Topology +go_node_manage_topology: false +go_node_topology_file: '{{ go_node_topology_container_dir }}/{{ go_node_network }}/topology.json' +go_node_topology_use_ledger_after_slot: 128908821 +go_node_topology_localroots: [] +go_node_topology_publicroots: [] +# Adjust for non-mainnet deployments +go_node_topology_bootstrap_peers: + - address: 'backbone.cardano.iog.io' + port: 3001 + - address: 'backbone.mainnet.emurgornd.com' + port: 3001 + - address: 'backbone.mainnet.cardanofoundation.org' + port: 3001 + +# Install chrony +chrony_enabled: true + +# Mithril configuration +go_node_restore_snapshot: true +go_node_snapshot_digest: 'latest' + +# Block Producer (also controls mounts for keys) +go_node_block_producer: false +go_node_shelley_kes_key: '{{ go_node_keys_container_dir }}/kes.skey' +go_node_shelley_opcert: '{{ go_node_keys_container_dir }}/node.cert' +go_node_shelley_vrf_key: '{{ go_node_keys_container_dir }}/vrf.skey' diff --git a/roles/go_node/meta/main.yml b/roles/go_node/meta/main.yml new file mode 100644 index 0000000..e8fe48d --- /dev/null +++ b/roles/go_node/meta/main.yml @@ -0,0 +1,3 @@ +galaxy_info: {} + +dependencies: [] diff --git a/roles/go_node/tasks/docker.yml b/roles/go_node/tasks/docker.yml new file mode 100644 index 0000000..293eb46 --- /dev/null +++ b/roles/go_node/tasks/docker.yml @@ -0,0 +1,54 @@ +--- +- name: Initialize go_node_docker_volumes fact + set_fact: + go_node_docker_volumes: '{{ go_node_docker_volumes | default([]) + [item] }}' + loop: + - '{{ go_node_ipc_dir }}:{{ go_node_ipc_container_dir }}' + - '{{ go_node_db_dir }}:{{ go_node_db_container_dir }}' + +- name: Add config to go_node_docker_volumes fact + set_fact: + go_node_docker_volumes: '{{ go_node_docker_volumes | default([]) + [item] }}' + loop: + - '{{ go_node_config_file }}:{{ go_node_config_file }}' + when: go_node_manage_config + +- name: Add topology to go_node_docker_volumes fact + set_fact: + go_node_docker_volumes: '{{ go_node_docker_volumes | default([]) + [item] }}' + loop: + - '{{ go_node_topology_file }}:{{ go_node_topology_file }}' + when: go_node_manage_topology + +- name: Add keys to go_node_docker_volumes fact + set_fact: + go_node_docker_volumes: '{{ go_node_docker_volumes | default([]) + [item] }}' + loop: + - '{{ go_node_keys_dir }}:{{ go_node_keys_container_dir }}' + when: go_node_block_producer | bool + +- name: Create container + docker_container: + name: '{{ go_node_docker_container_name }}' + image: '{{ go_node_docker_image }}' + command: + - run + restart_policy: unless-stopped + ports: + - '{{ go_node_port }}:{{ go_node_container_port }}' + - '{{ go_node_metrics_port }}:{{ go_node_metrics_container_port }}' + env: + CARDANO_BLOCK_PRODUCER: '{{ go_node_block_producer | string }}' + CARDANO_CONFIG: '{{ go_node_config_file }}' + CARDANO_DATABASE_PATH: '{{ go_node_db_container_dir }}' + CARDANO_NETWORK: '{{ go_node_network }}' + CARDANO_NODE_SOCKET_PATH: '{{ go_node_ipc_container_dir }}/{{ go_node_socket_name }}' + CARDANO_PORT: '{{ go_node_port | string }}' + CARDANO_SHELLEY_KES_KEY: '{{ go_node_shelley_kes_key }}' + CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE: '{{ go_node_shelley_opcert }}' + CARDANO_SHELLEY_VRF_KEY: '{{ go_node_shelley_vrf_key }}' + CARDANO_SOCKET_PATH: '{{ go_node_ipc_container_dir }}/{{ go_node_socket_name }}' + CARDANO_TOPOLOGY: '{{ go_node_topology_file }}' + RESTORE_SNAPSHOT: '{{ go_node_restore_snapshot | string }}' + SNAPSHOT_DIGEST: '{{ go_node_snapshot_digest }}' + volumes: '{{ go_node_docker_volumes | list }}' diff --git a/roles/go_node/tasks/main.yml b/roles/go_node/tasks/main.yml new file mode 100644 index 0000000..8117467 --- /dev/null +++ b/roles/go_node/tasks/main.yml @@ -0,0 +1,50 @@ +--- +- name: Check install method + vars: + _allowed_install_methods: ['docker'] + ansible.builtin.assert: + that: + - go_node_install_method in _allowed_install_methods + fail_msg: 'The specified install method ({{ go_node_install_method }}) is not one of the allowed values ({{ _allowed_install_methods | join(", ") }})' + +- name: Install chrony + package: + name: chrony + state: present + when: chrony_enabled + +- name: Create directories for persistent data + ansible.builtin.file: + state: directory + path: '{{ item }}' + owner: '{{ go_node_user | string }}' + group: '{{ go_node_group | string }}' + mode: '0755' + loop: + - '{{ go_node_db_dir }}' + - '{{ go_node_ipc_dir }}' + +- name: Create directories for topology + ansible.builtin.file: + state: directory + path: '{{ item }}' + owner: '{{ go_node_user | string }}' + group: '{{ go_node_group | string }}' + mode: '0755' + loop: + - '{{ go_node_topology_dir }}' + when: go_node_manage_topology + +- name: Generate custom topology config + template: + dest: '{{ go_node_topology_file }}' + src: custom-topology.json.j2 + owner: '{{ go_node_user | string }}' + group: '{{ go_node_group | string }}' + mode: 0644 + register: cardano_topology + when: go_node_manage_topology + +- name: Include docker-related tasks + ansible.builtin.include_tasks: docker.yml + when: go_node_install_method == 'docker' diff --git a/roles/go_node/templates/custom-topology.json.j2 b/roles/go_node/templates/custom-topology.json.j2 new file mode 100644 index 0000000..2bb5001 --- /dev/null +++ b/roles/go_node/templates/custom-topology.json.j2 @@ -0,0 +1,56 @@ +{ +{% set peer_count = go_node_topology_bootstrap_peers | length %} +{% if peer_count > 0 %} + "bootstrapPeers": [ +{% for peer in go_node_topology_bootstrap_peers %} + { + "address": "{{ peer.address }}", + "port": {{ peer.port | int }} +{% if loop.index == peer_count %} + } +{% else %} + }, +{% endif %} +{% endfor %} + ], +{% endif %} + "localRoots": [ + { + "accessPoints": [ +{% set peer_count = go_node_topology_localroots | length %} +{% for peer in go_node_topology_localroots %} + { + "address": "{{ peer.address }}", + "port": {{ peer.port | int }} +{% if loop.index == peer_count %} + } +{% else %} + }, +{% endif %} +{% endfor %} + ], + "advertise": false, + "trustable": false, + "valency": 1 + } + ], + "publicRoots": [ + { + "accessPoints": [ +{% set peer_count = go_node_topology_publicroots | length %} +{% for peer in go_node_topology_publicroots %} + { + "address": "{{ peer.address }}", + "port": {{ peer.port | int }} +{% if loop.index == peer_count %} + } +{% else %} + }, +{% endif %} +{% endfor %} + ], + "advertise": false + } + ], + "useLedgerAfterSlot": {{ go_node_topology_use_ledger_after_slot }} +}