Skip to content

Commit 9409345

Browse files
committed
Add playbook for root block voting
1 parent ef46295 commit 9409345

File tree

2 files changed

+234
-0
lines changed

2 files changed

+234
-0
lines changed

cmd/bootstrap/transit/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,19 @@ Running `transit push-transit-key` will perform the following actions:
8383
- `transit-key.priv.<id>`
8484
1. Upload the node's public files to the server
8585
- `transit-key.pub.<id>`
86+
87+
## Ansible Playbook
88+
89+
The `root_block_voting.yml` Ansible playbook is used to automate the process of pulling the root block and random beacon key, generating the root block vote, and pushing the vote to the server. Please refer to this as an example of how to use the transit script in an automated environment.
90+
91+
Example usage:
92+
93+
```shell
94+
ansible-playbook -i inventories/mainnet/mainnet26.yml/ vote_on_root_block.yml \
95+
-e "boot_tools_tar=https://storage.googleapis.com/flow-genesis-bootstrap/boot-tools.tar" \
96+
-e "output_directory=/var/flow/bootstrap" \
97+
-e "network_version_token=mainnet-26" \
98+
-e "genesis_bucket=flow-genesis-bootstrap" \
99+
-e force_repull_transit=true
100+
```
101+
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
---
2+
- name: Prepare and sign root block
3+
hosts: consensus
4+
become: true
5+
gather_facts: false
6+
7+
vars:
8+
# Required inputs (no defaults)
9+
# http(s) URL or absolute local path to boot-tools.tar (on controller)
10+
boot_tools_tar: "{{ boot_tools_tar }}"
11+
genesis_bucket: "{{ genesis_bucket }}"
12+
network_version_token: "{{ network_version_token }}"
13+
output_directory: "{{ output_directory }}"
14+
15+
# Derived
16+
transit_path: "{{ output_directory }}/transit"
17+
_is_url: "{{ (boot_tools_tar is string) and (boot_tools_tar is match('^https?://')) }}"
18+
19+
# Flag to force re-pull/install of transit
20+
force_repull_transit: false
21+
22+
pre_tasks:
23+
- name: Validate required inputs are provided
24+
assert:
25+
that:
26+
- boot_tools_tar is defined and (boot_tools_tar | string | length) > 0
27+
- output_directory is defined and (output_directory | string | length) > 0
28+
- network_version_token is defined and (network_version_token | string | length) > 0
29+
- genesis_bucket is defined and (genesis_bucket | string | length) > 0
30+
fail_msg: >-
31+
Missing one or more required inputs: boot_tools_tar, output_directory,
32+
network_version_token, genesis_bucket.
33+
tags: [validate]
34+
35+
- name: Validate output_directory is an absolute path
36+
assert:
37+
that:
38+
- output_directory is match('^/')
39+
fail_msg: "output_directory must be an absolute path (e.g., /opt/flow/transit-bin)."
40+
tags: [validate]
41+
42+
- name: Validate boot_tools_tar looks like a URL or an absolute file path
43+
vars:
44+
_looks_like_path: "{{ (not _is_url) and (boot_tools_tar is match('^/')) }}"
45+
assert:
46+
that:
47+
- _is_url or _looks_like_path
48+
fail_msg: "boot_tools_tar must be an http(s) URL or an absolute local path on the controller."
49+
tags: [validate]
50+
51+
tasks:
52+
- name: Check if output directory exists
53+
stat:
54+
path: "{{ output_directory }}"
55+
register: dir_stat
56+
57+
- name: Create output directory (skip if exists)
58+
file:
59+
path: "{{ output_directory }}"
60+
state: directory
61+
mode: "0755"
62+
when: not dir_stat.stat.exists
63+
64+
- name: Check if transit already exists in output directory
65+
stat:
66+
path: "{{ transit_path }}"
67+
register: transit_stat
68+
when: not force_repull_transit
69+
70+
- name: Decide if we should fetch/reinstall transit
71+
set_fact:
72+
should_fetch_transit: "{{ true if force_repull_transit else (not transit_stat.stat.exists) }}"
73+
74+
- block:
75+
- name: Create temporary working directory
76+
tempfile:
77+
state: directory
78+
suffix: boottools
79+
register: tmpdir
80+
81+
- name: Download boot-tools.tar to temp directory (URL)
82+
get_url:
83+
url: "{{ boot_tools_tar }}"
84+
dest: "{{ tmpdir.path }}/boot-tools.tar"
85+
mode: "0644"
86+
force: true
87+
timeout: 120
88+
when: _is_url
89+
90+
- name: Copy boot-tools.tar to temp directory (local controller path)
91+
copy:
92+
src: "{{ boot_tools_tar }}"
93+
dest: "{{ tmpdir.path }}/boot-tools.tar"
94+
mode: "0644"
95+
when: not _is_url
96+
97+
- name: Extract boot-tools.tar into temp directory
98+
unarchive:
99+
src: "{{ tmpdir.path }}/boot-tools.tar"
100+
dest: "{{ tmpdir.path }}"
101+
remote_src: true
102+
103+
- name: Find the transit binary inside the extracted boot tools
104+
find:
105+
paths: "{{ tmpdir.path }}"
106+
patterns: "transit"
107+
file_type: file
108+
recurse: true
109+
register: transit_found
110+
111+
- name: Ensure transit binary was found in boot-tools.tar
112+
assert:
113+
that:
114+
- (transit_found.files | length) > 0
115+
fail_msg: "Could not locate 'transit' inside boot-tools.tar."
116+
117+
- name: Install transit into output directory
118+
copy:
119+
src: "{{ (transit_found.files | first).path }}"
120+
dest: "{{ transit_path }}"
121+
mode: "0755"
122+
remote_src: true
123+
124+
- name: Cleanup temporary working directory
125+
file:
126+
path: "{{ tmpdir.path }}"
127+
state: absent
128+
when: should_fetch_transit
129+
130+
- name: Ensure transit binary is executable
131+
file:
132+
path: "{{ transit_path }}"
133+
mode: "0755"
134+
state: file
135+
136+
# --- Transit commands ---
137+
- name: Pull root block command
138+
command:
139+
argv:
140+
- "{{ transit_path }}"
141+
- pull-root-block
142+
- -t
143+
- "{{ network_version_token }}"
144+
- -b
145+
- /var/flow/bootstrap
146+
- -o
147+
- "{{ output_directory }}"
148+
- -g
149+
- "{{ genesis_bucket }}"
150+
register: pull_root_block_result
151+
ignore_errors: false
152+
153+
- name: Show output of pull root block command
154+
debug:
155+
msg:
156+
- "stdout: {{ pull_root_block_result.stdout | default('') }}"
157+
- "stderr: {{ pull_root_block_result.stderr | default('') }}"
158+
159+
- name: Generate root block vote
160+
command:
161+
argv:
162+
- "{{ transit_path }}"
163+
- generate-root-block-vote
164+
- -b
165+
- /var/flow/bootstrap
166+
- -o
167+
- "{{ output_directory }}"
168+
register: gen_vote_result
169+
ignore_errors: false
170+
171+
- name: Show output of generate root block vote command
172+
debug:
173+
msg:
174+
- "stdout: {{ gen_vote_result.stdout | default('') }}"
175+
- "stderr: {{ gen_vote_result.stderr | default('') }}"
176+
177+
- name: Push root block vote
178+
command:
179+
argv:
180+
- "{{ transit_path }}"
181+
- push-root-block-vote
182+
- -t
183+
- "{{ network_version_token }}"
184+
- -b
185+
- /var/flow/bootstrap
186+
- -d
187+
- "{{ output_directory }}"
188+
- -g
189+
- "{{ genesis_bucket }}"
190+
register: push_vote_result
191+
ignore_errors: false
192+
193+
- name: Show output of push root block vote
194+
debug:
195+
msg:
196+
- "stdout: {{ push_vote_result.stdout | default('') }}"
197+
- "stderr: {{ push_vote_result.stderr | default('') }}"
198+
199+
- name: Get node id from file
200+
command: cat /var/flow/bootstrap/public-root-information/node-id
201+
register: nodeid_result
202+
203+
- name: Strip whitespace from node id
204+
set_fact:
205+
node_id: "{{ nodeid_result.stdout | trim }}"
206+
207+
- name: Check if root block vote file exists in GCS
208+
command: >
209+
gsutil ls gs://{{ genesis_bucket }}/{{ network_version_token }}/root-block-vote.{{ node_id }}.json
210+
register: gsutil_result
211+
ignore_errors: true
212+
213+
- name: Assert root block vote file exists in bucket
214+
assert:
215+
that:
216+
- gsutil_result.rc == 0
217+
fail_msg: "Root block vote file not found in bucket"
218+

0 commit comments

Comments
 (0)