-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathgenerate-shadow-yaml.sh
More file actions
executable file
·207 lines (171 loc) · 6.07 KB
/
Copy pathgenerate-shadow-yaml.sh
File metadata and controls
executable file
·207 lines (171 loc) · 6.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#!/bin/bash
set -e
# generate-shadow-yaml.sh — Generate shadow.yaml from validator-config.yaml
#
# Multi-client: reuses existing client-cmds/<client>-cmd.sh to get node_binary.
# Works for zeam, ream, lantern, gean, or any client with a *-cmd.sh file.
#
# Usage:
# ./generate-shadow-yaml.sh <genesis-dir> --project-root <path> [--stop-time 360s] [--output shadow.yaml]
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
show_usage() {
cat << EOF
Usage: $0 <genesis-dir> --project-root <path> [--stop-time 360s] [--output shadow.yaml]
Generate a Shadow network simulator configuration (shadow.yaml) from validator-config.yaml.
Arguments:
genesis-dir Path to genesis directory containing validator-config.yaml
Options:
--project-root <path> Project root directory (parent of lean-quickstart). Required.
--stop-time <time> Shadow simulation stop time (default: 360s)
--output <path> Output shadow.yaml path (default: <project-root>/shadow.yaml)
This script is client-agnostic. It reads node names from validator-config.yaml,
extracts the client name from the node prefix (e.g., zeam_0 → zeam), and sources
the corresponding client-cmds/<client>-cmd.sh to generate per-node arguments.
EOF
exit 1
}
# ========================================
# Parse arguments
# ========================================
if [ -z "$1" ] || [ "${1:0:1}" == "-" ]; then
show_usage
fi
GENESIS_DIR="$(cd "$1" && pwd)"
shift
PROJECT_ROOT=""
STOP_TIME="360s"
OUTPUT_FILE=""
while [[ $# -gt 0 ]]; do
case "$1" in
--project-root)
if [ -n "$2" ] && [ "${2:0:1}" != "-" ]; then
PROJECT_ROOT="$(cd "$2" && pwd)"
shift 2
else
echo "❌ Error: --project-root requires a path"
exit 1
fi
;;
--stop-time)
if [ -n "$2" ]; then
STOP_TIME="$2"
shift 2
else
echo "❌ Error: --stop-time requires a value"
exit 1
fi
;;
--output)
if [ -n "$2" ]; then
OUTPUT_FILE="$2"
shift 2
else
echo "❌ Error: --output requires a path"
exit 1
fi
;;
*)
echo "❌ Unknown option: $1"
show_usage
;;
esac
done
if [ -z "$PROJECT_ROOT" ]; then
echo "❌ Error: --project-root is required"
show_usage
fi
if [ -z "$OUTPUT_FILE" ]; then
OUTPUT_FILE="$PROJECT_ROOT/shadow.yaml"
fi
VALIDATOR_CONFIG="$GENESIS_DIR/validator-config.yaml"
if [ ! -f "$VALIDATOR_CONFIG" ]; then
echo "❌ Error: validator-config.yaml not found at $VALIDATOR_CONFIG"
exit 1
fi
# ========================================
# Read nodes from validator-config.yaml
# ========================================
node_names=($(yq eval '.validators[].name' "$VALIDATOR_CONFIG"))
node_count=${#node_names[@]}
if [ "$node_count" -eq 0 ]; then
echo "❌ Error: No validators found in $VALIDATOR_CONFIG"
exit 1
fi
echo "🔧 Generating shadow.yaml for $node_count nodes..."
# ========================================
# Write shadow.yaml preamble
# ========================================
cat > "$OUTPUT_FILE" << EOF
# Auto-generated Shadow network simulator configuration
# Generated from: $VALIDATOR_CONFIG
# Nodes: ${node_names[*]}
general:
model_unblocked_syscall_latency: true
stop_time: $STOP_TIME
experimental:
native_preemption_enabled: true
network:
graph:
type: 1_gbit_switch
hosts:
EOF
# ========================================
# Generate per-node host entries
# ========================================
for i in "${!node_names[@]}"; do
item="${node_names[$i]}"
# Extract client name from node prefix (zeam_0 → zeam, leanspec_0 → leanspec)
IFS='_' read -r -a elements <<< "$item"
client="${elements[0]}"
# DNS-valid hostname: underscores → hyphens (Shadow requirement)
hostname="${item//_/-}"
# Extract IP from validator-config
ip=$(yq eval ".validators[$i].enrFields.ip" "$VALIDATOR_CONFIG")
# Set up environment for parse-vc.sh and client-cmd.sh
# These scripts expect: $item, $configDir, $dataDir, $scriptDir, $validatorConfig
export scriptDir="$SCRIPT_DIR"
export configDir="$GENESIS_DIR"
export dataDir="$PROJECT_ROOT/shadow.data/hosts/$hostname"
export validatorConfig="$GENESIS_DIR"
# Source parse-vc.sh to extract per-node config (quicPort, metricsPort, apiPort, etc.)
# parse-vc.sh uses $item and $configDir
source "$SCRIPT_DIR/parse-vc.sh"
# Source client-cmd.sh to get node_binary
node_setup="binary"
client_cmd="$SCRIPT_DIR/client-cmds/${client}-cmd.sh"
if [ ! -f "$client_cmd" ]; then
echo "❌ Error: Client command script not found: $client_cmd"
echo " Available clients:"
ls "$SCRIPT_DIR/client-cmds/"*-cmd.sh 2>/dev/null | sed 's/.*\// /' | sed 's/-cmd.sh//'
exit 1
fi
source "$client_cmd"
# node_binary is now set by the client-cmd.sh script
# Convert relative paths to absolute paths for Shadow
# Extract the binary path (first word) and args (rest)
binary_path=$(echo "$node_binary" | awk '{print $1}')
binary_args=$(echo "$node_binary" | sed "s|^[^ ]*||")
# Make binary path absolute
if [[ "$binary_path" != /* ]]; then
binary_path="$(cd "$(dirname "$binary_path")" 2>/dev/null && pwd)/$(basename "$binary_path")" 2>/dev/null || binary_path="$PROJECT_ROOT/${binary_path#./}"
fi
# Make all path args absolute: replace $configDir, $dataDir references with absolute paths
# The client-cmd.sh already uses $configDir and $dataDir which we set to absolute paths
# Write host entry
cat >> "$OUTPUT_FILE" << EOF
$hostname:
network_node_id: 0
ip_addr: $ip
processes:
- path: $binary_path
args: >-
$binary_args
start_time: 1s
expected_final_state: running
EOF
echo " ✅ $item → $hostname ($ip) [$client]"
done
echo ""
echo "📄 Shadow config written to: $OUTPUT_FILE"
echo " Stop time: $STOP_TIME"
echo " Nodes: $node_count"