Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions ansible-devnet/genesis/validator-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,12 @@ validators:
ip: "46.62.163.74"
quic: 9001
metricsPort: 8081
count: 1

- name: "ethlambda_0"
privkey: "299550529a79bc2dce003747c52fb0639465c893e00b0440ac66144d625e066a"
enrFields:
ip: "TBD"
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IP address is set to a placeholder value "TBD" instead of an actual IP address. This should be replaced with the actual IP address for the ethlambda node in the ansible-devnet environment, similar to how other nodes in the file have actual IP addresses configured.

Suggested change
ip: "TBD"
ip: "127.0.0.1"

Copilot uses AI. Check for mistakes.
quic: 9001
metricsPort: 8081
count: 1
12 changes: 10 additions & 2 deletions ansible/playbooks/deploy-single-node.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,15 @@
- grandine
- deploy

- name: Deploy Ethlambda node
include_role:
name: ethlambda
when: client_type == "ethlambda"
tags:
- ethlambda
- deploy

- name: Fail if unknown client type
fail:
msg: "Unknown client type '{{ client_type }}' for node '{{ node_name }}'. Expected: zeam, ream, qlean, lantern, lighthouse or grandine"
when: client_type not in ["zeam", "ream", "qlean", "lantern", "lighthouse", "grandine"]
msg: "Unknown client type '{{ client_type }}' for node '{{ node_name }}'. Expected: zeam, ream, qlean, lantern, lighthouse, grandine or ethlambda"
when: client_type not in ["zeam", "ream", "qlean", "lantern", "lighthouse", "grandine", "ethlambda"]
7 changes: 7 additions & 0 deletions ansible/roles/ethlambda/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
# Default variables for ethlambda role
# Note: These are fallback defaults. Actual values are extracted from client-cmds/ethlambda-cmd.sh
# in the tasks/main.yml file. These defaults are used if extraction fails.

ethlambda_docker_image: "ghcr.io/lambdaclass/ethlambda:latest"
deployment_mode: docker # docker or binary
100 changes: 100 additions & 0 deletions ansible/roles/ethlambda/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
# Ethlambda role: Deploy and manage Ethlambda nodes
# Converts client-cmds/ethlambda-cmd.sh logic to Ansible tasks

- name: Extract docker image from client-cmd.sh
shell: |
# Extract the first word (docker image) from node_docker line
# playbook_dir points to ansible/playbooks, go up two levels to reach project root
project_root="$(cd '{{ playbook_dir }}/../..' && pwd)"
grep -E '^node_docker=' "$project_root/client-cmds/ethlambda-cmd.sh" | head -1 | sed -E 's/.*node_docker="([^ "]+).*/\1/'
register: ethlambda_docker_image_raw
changed_when: false
delegate_to: localhost
run_once: true

- name: Extract deployment mode from client-cmd.sh
shell: |
# Extract the value from node_setup line
# playbook_dir points to ansible/playbooks, go up two levels to reach project root
project_root="$(cd '{{ playbook_dir }}/../..' && pwd)"
grep -E '^node_setup=' "$project_root/client-cmds/ethlambda-cmd.sh" | head -1 | sed -E 's/.*node_setup="([^"]+)".*/\1/'
register: ethlambda_deployment_mode_raw
changed_when: false
delegate_to: localhost
run_once: true

- name: Set docker image and deployment mode from client-cmd.sh
set_fact:
ethlambda_docker_image: "{{ ethlambda_docker_image_raw.stdout | trim | default('ghcr.io/lambdaclass/ethlambda:latest') }}"
deployment_mode: "{{ ethlambda_deployment_mode_raw.stdout | trim | default('docker') }}"

- name: Extract node configuration from validator-config.yaml
shell: |
yq eval ".validators[] | select(.name == \"{{ node_name }}\") | .{{ item }}" "{{ genesis_dir }}/validator-config.yaml"
register: ethlambda_node_config
changed_when: false
loop:
- enrFields.quic
- metricsPort
when: node_name is defined

- name: Set node ports
set_fact:
ethlambda_quic_port: "{{ ethlambda_node_config.results[0].stdout }}"
ethlambda_metrics_port: "{{ ethlambda_node_config.results[1].stdout }}"
when: ethlambda_node_config is defined

- name: Ensure node key file exists
stat:
path: "{{ genesis_dir }}/{{ node_name }}.key"
register: node_key_stat

- name: Debug node key file check
debug:
msg: "Checking for key file at {{ genesis_dir }}/{{ node_name }}.key - exists: {{ node_key_stat.stat.exists | default('undefined') }}"

- name: Fail if node key file is missing
fail:
msg: "Node key file {{ node_name }}.key not found in {{ genesis_dir }}"
when: not (node_key_stat.stat.exists | default(false))

- name: Clean node data directory
file:
path: "{{ data_dir }}/{{ node_name }}"
state: absent
when: clean_data | default(false) | bool

- name: Create node data directory
file:
path: "{{ data_dir }}/{{ node_name }}"
state: directory
mode: "0755"

- name: Deploy Ethlambda node using Docker
block:
- name: Stop existing Ethlambda container (if any)
command: docker rm -f {{ node_name }}
register: ethlambda_stop
failed_when: false
changed_when: ethlambda_stop.rc == 0

- name: Start Ethlambda container
command: >-
docker run -d
--pull=always
--name {{ node_name }}
--restart unless-stopped
--network host
-v {{ genesis_dir }}:/config:ro
-v {{ data_dir }}/{{ node_name }}:/data
{{ ethlambda_docker_image }}
--custom-network-config-dir /config
--gossipsub-port {{ ethlambda_quic_port }}
--node-id {{ node_name }}
--node-key /config/{{ node_name }}.key
--metrics-address 0.0.0.0
--metrics-port {{ ethlambda_metrics_port }}
register: ethlambda_container
changed_when: ethlambda_container.rc == 0
when: deployment_mode == 'docker'
25 changes: 25 additions & 0 deletions client-cmds/ethlambda-cmd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

#-----------------------ethlambda setup----------------------

binary_path="$scriptDir/../ethlambda/target/release/ethlambda"

# Command when running as binary
node_binary="$binary_path \
--custom-network-config-dir $configDir \
--gossipsub-port $quicPort \
--node-id $item \
--node-key $configDir/$item.key \
--metrics-address 0.0.0.0 \
--metrics-port $metricsPort"

# Command when running as docker container
node_docker="ghcr.io/lambdaclass/ethlambda:latest \
--custom-network-config-dir /config \
--gossipsub-port $quicPort \
--node-id $item \
--node-key /config/$item.key \
--metrics-address 0.0.0.0 \
--metrics-port $metricsPort"

node_setup="docker"
4 changes: 3 additions & 1 deletion generate-ansible-inventory.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,16 @@ all:
hosts: {}
grandine_nodes:
hosts: {}
ethlambda_nodes:
hosts: {}
EOF

# Extract node information from validator-config.yaml
nodes=($(yq eval '.validators[].name' "$VALIDATOR_CONFIG"))

# Process each node and generate inventory entries
for node_name in "${nodes[@]}"; do
# Extract client type (zeam, ream, qlean, lantern, lighthouse, grandine)
# Extract client type (zeam, ream, qlean, lantern, lighthouse, grandine, ethlambda)
IFS='_' read -r -a elements <<< "$node_name"
client_type="${elements[0]}"
group_name="${client_type}_nodes"
Expand Down
15 changes: 13 additions & 2 deletions local-devnet/genesis/validator-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ validators:
quic: 9004
metricsPort: 8084
count: 1

- name: "lighthouse_0"
# node id a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2
# peer id 16Uiu2HAm7TYVs6qvDKnrovd9m4vvRikc4HPXm1WyLumKSe5fHxBv
Expand All @@ -66,4 +66,15 @@ validators:
ip: "127.0.0.1"
quic: 9006
metricsPort: 8086
count: 1
count: 1

- name: "ethlambda_0"
# node id a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2
# peer id 16Uiu2HAmPV5jU62WtmDkCEmfq1jzbBDkGbHNsDN78gJyvmv2TuC5
privkey: "299550529a79bc2dce003747c52fb0639465c893e00b0440ac66144d625e066a"
# verify /ip4/127.0.0.1/udp/9007/quic-v1/p2p/16Uiu2HAmPV5jU62WtmDkCEmfq1jzbBDkGbHNsDN78gJyvmv2TuC5
enrFields:
ip: "127.0.0.1"
quic: 9007
metricsPort: 8087
count: 1
2 changes: 1 addition & 1 deletion run-ansible.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ fi
# Update inventory with SSH key file and user if provided
if command -v yq &> /dev/null; then
# Get all remote host groups (zeam_nodes, ream_nodes, qlean_nodes, lantern_nodes, lighthouse_nodes)
for group in zeam_nodes ream_nodes qlean_nodes lantern_nodes lighthouse_nodes grandine_nodes; do
for group in zeam_nodes ream_nodes qlean_nodes lantern_nodes lighthouse_nodes grandine_nodes ethlambda_nodes; do
# Get all hosts in this group
hosts=$(yq eval ".all.children.$group.hosts | keys | .[]" "$INVENTORY_FILE" 2>/dev/null || echo "")
for host in $hosts; do
Expand Down