-
Notifications
You must be signed in to change notification settings - Fork 1
/
run_auto_config.sh
executable file
·393 lines (329 loc) · 14.9 KB
/
run_auto_config.sh
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
#!/bin/bash
CFG_PATH=/var/tmp
strip_quotes() {
local value="$1"
# Remove double quotes from the beginning and end
value="${value%\"}"
value="${value#\"}"
# Remove single quotes from the beginning and end
value="${value%\'}"
value="${value#\'}"
echo "$value"
}
create_config_husarnet() {
if [ -z "${ROS_DOMAIN_ID}" ]; then
export ROS_DOMAIN_ID=0
fi
export LOCAL_IP=$(echo $husarnet_api_response | yq .result.local_ip)
if [[ -z "$ROS_DISCOVERY_SERVER" ]]; then
echo "Launching Initial Peers config"
yq -i '.participants += load("/participant.husarnet.wan.yaml")' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
yq -i '(.participants[] | select(.name == "HusarnetParticipant").listening-addresses[0].ip) = strenv(LOCAL_IP)' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
yq -i '(.participants[] | select(.name == "HusarnetParticipant").connection-addresses[0].ip) = strenv(LOCAL_IP)' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
else
echo "Launching ROS Discovery Server config"
yq -i '.participants += load("/participant.husarnet.ds.yaml")' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
# Splitting the string into an array using semicolon as the delimiter
IFS=';' read -ra DS_LIST <<<"$ROS_DISCOVERY_SERVER"
# Process the array
NEW_LIST=()
for entry in "${DS_LIST[@]}"; do
# If the entry is empty, replace it with "_EMPTY_"
if [ -z "$entry" ]; then
NEW_LIST+=("_EMPTY_")
else
NEW_LIST+=("$entry")
fi
done
# Join back into a string
IFS=";"
NEW_STR="${NEW_LIST[*]}"
# Splitting the modified string into an array for final result
IFS=';' read -ra DS_LIST <<<"$NEW_STR"
# Regular expression to match hostname:port or [ipv6addr]:port
DS_REGEX="^(([a-zA-Z0-9-]+)(:[0-9]+)?|\[(([a-fA-F0-9]{1,4}:){1,7}[a-fA-F0-9]{1,4}|[a-fA-F0-9]{0,4})\](:[0-9]+)?)$"
# creating config for super_client
cp /superclient.template.xml $CFG_PATH/superclient.xml
yq -i '.dds.profiles.participant.rtps.builtin.discovery_config.discoveryServersList.RemoteServer = [ "placeholder1", "placeholder2" ]' $CFG_PATH/superclient.xml
# Loop over Discovery Servers
current_id=0
for ds in ${DS_LIST[@]}; do
# If the current element is _EMPTY_, skip further processing in this iteration
if [ "$ds" = "_EMPTY_" ]; then
((current_id++))
continue
fi
if [[ "${ds}" =~ $DS_REGEX ]]; then
# Extract HOST and PORT from the match results
if [[ -n ${BASH_REMATCH[2]} ]]; then
# If it's in hostname:port format
HOST="${BASH_REMATCH[2]}"
export PORT="${BASH_REMATCH[3]//:/}"
if [ -z "$PORT" ]; then
export PORT="11811"
fi
ipv6=$(echo $husarnet_api_response | yq .result.host_table | yq -r ".$HOST")
if [[ "$ipv6" == "null" || -z "$ipv6" ]]; then
echo "Error: IPv6 address not found for $HOST"
exit 1
else
export HOST=$ipv6
fi
elif [[ -n ${BASH_REMATCH[4]} ]]; then
# If it's in [ipv6addr]:port format
HOST="${BASH_REMATCH[4]}"
export PORT="${BASH_REMATCH[6]//:/}"
if [ -z "$PORT" ]; then
export PORT="11811"
fi
# Extract all IP addresses from the host_table
IP_ADDRESSES=$(echo $husarnet_api_response | yq '.result.host_table[]')
# Iterate over each address in IP_ADDRESSES
address_found=false
IFS=$'\n' # Set Internal Field Separator to newline for the loop
for address in $IP_ADDRESSES; do
if [[ "$address" == "$HOST" ]]; then
address_found=true
break
fi
done
if $address_found; then
export HOST
else
echo "Error: $HOST address not found"
exit 1
fi
fi
if [[ ! ($PORT -le 65535) ]]; then
echo "Discovery Server Port is not a valid number or is outside the valid range (0-65535)."
exit 1
fi
export SERVER_ID=${current_id}
((current_id++))
if [[ $LOCAL_IP == $HOST ]]; then
echo "> Server config"
export DISCOVERY_SERVER_ID=$SERVER_ID
yq -i '(.participants[] | select(.name == "HusarnetParticipant").listening-addresses) +=
{
"ip": strenv(HOST),
"port": env(PORT),
"transport": "udp"
}' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
else
echo "> Client config"
yq -i '(.participants[] | select(.name == "HusarnetParticipant").connection-addresses) +=
{
"discovery-server-guid":
{
"ros-discovery-server": true,
"id": env(SERVER_ID)
},
"addresses":
[
{
"ip": strenv(HOST),
"port": env(PORT),
"transport": "udp"
}
]
}' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
fi
echo "[$HOST]:$PORT (Server ID: $SERVER_ID)"
# XML config for client (optional)
# # Convert the decimal to a hexadecimal value
hex_server_id=$(printf '%.2X' $SERVER_ID)
# Replace XX in GUID_PREFIX with the hexadecimal value
export GUID_PREFIX=$(echo "44.53.XX.5F.45.50.52.4F.53.49.4D.41" | sed "s/XX/$hex_server_id/")
yq -i '.dds.profiles.participant.rtps.builtin.discovery_config.discoveryServersList.RemoteServer +=
{
"+@prefix": env(GUID_PREFIX),
"metatrafficUnicastLocatorList":
{
"locator":
{
"udpv6":
{
"address": env(HOST),
"port": env(PORT)
}
}
}
}' $CFG_PATH/superclient.xml
else
echo "Error: ROS_DISCOVERY_SERVER does not have a valid format: $ds"
exit 1
fi
done
# Check if DISCOVERY_SERVER_ID is not set or outside the range 0-255
if [[ ! "$DISCOVERY_SERVER_ID" =~ ^[0-9]+$ ]] || [[ "$DISCOVERY_SERVER_ID" -lt 0 ]] || [[ "$DISCOVERY_SERVER_ID" -gt 255 ]]; then
echo "DISCOVERY_SERVER_ID=${DISCOVERY_SERVER_ID} is not valid number. Setting a random value (10-255)."
# Generate a random value between 10 and 255 and export it
export DISCOVERY_SERVER_ID=$((RANDOM % 246 + 10))
fi
yq -i '(.participants[] | select(.name == "HusarnetParticipant").discovery-server-guid.id) = env(DISCOVERY_SERVER_ID)' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
yq -i 'del(.dds.profiles.participant.rtps.builtin.discovery_config.discoveryServersList.RemoteServer[0])' $CFG_PATH/superclient.xml
yq -i 'del(.dds.profiles.participant.rtps.builtin.discovery_config.discoveryServersList.RemoteServer[0])' $CFG_PATH/superclient.xml
echo "> DS Local Server ID: $DISCOVERY_SERVER_ID"
echo "> TIP: Find a Super Client config in $CFG_PATH/superclient.xml"
fi
}
WHITELIST_INTERFACES=$(strip_quotes "$WHITELIST_INTERFACES")
ROS_DISCOVERY_SERVER=$(strip_quotes "$ROS_DISCOVERY_SERVER")
FILTER=$(strip_quotes "$FILTER")
run_auto_config() {
cp config.base.yaml $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
if [[ -n "${CONFIG_BASE}" ]]; then
yq -i '. * env(CONFIG_BASE)' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
fi
# Verify that PARTICIPANTS is set and not empty
if [ -z "$PARTICIPANTS" ]; then
echo "Error: PARTICIPANTS environment variable is not set."
exit 1
fi
# # Regex to verify the format
# if ! [[ $PARTICIPANTS =~ ^([a-z]+,?)*$ ]]; then
# echo "Error: PARTICIPANTS env format is incorrect."
# exit 1
# fi
# Regex to verify the format
if ! [[ $PARTICIPANTS =~ ^([a-z]+(-[a-zA-Z0-9*]+)?,?)+$ ]]; then
echo "Error: PARTICIPANTS env format is incorrect."
exit 1
fi
# Initialize all participant variables to false
PARTICIPANT_HUSARNET_ENABLED=false
PARTICIPANT_LO_ENABLED=false
PARTICIPANT_SHM_ENABLED=false
PARTICIPANT_LAN_ENABLED=false
PARTICIPANT_ECHO_ENABLED=false
PARTICIPANT_IF_LIST=()
# Function to enable a participant
enable_participant() {
case $1 in
husarnet)
PARTICIPANT_HUSARNET_ENABLED=true
;;
lo)
PARTICIPANT_LO_ENABLED=true
;;
shm)
PARTICIPANT_SHM_ENABLED=true
;;
lan)
PARTICIPANT_LAN_ENABLED=true
;;
echo)
PARTICIPANT_ECHO_ENABLED=true
;;
if-*)
interface_pattern=${1#if-}
if [[ $interface_pattern == *"*"* ]]; then
# Handle wildcard interface patterns
for intf in /sys/class/net/${interface_pattern#*/}; do
intf=${intf#/sys/class/net/}
if [[ -d "/sys/class/net/$intf" ]]; then
PARTICIPANT_IF_LIST+=("$intf")
fi
done
else
# Handle specific interface name
PARTICIPANT_IF_LIST+=("$interface_pattern")
fi
;;
*)
# Ignore any other values
;;
esac
}
# Enable participants based on the PARTICIPANTS variable
IFS=',' read -ra ADDR <<<"$PARTICIPANTS"
for i in "${ADDR[@]}"; do
enable_participant "$i"
done
# Check the value of HUSARNET_PARTICIPANT_ENABLED
if [[ $PARTICIPANT_HUSARNET_ENABLED == false ]]; then
# echo "Using LAN setup."
echo "Don't using Husarnet participants."
export husarnet_ready=false
else
echo ">> Husarnet participant enabled"
echo "Checking if Husarnet API (http://$HUSARNET_API_HOST:16216) is ready "
for i in {1..7}; do
husarnet_api_response=$(curl -s http://$HUSARNET_API_HOST:16216/api/status)
# Check the exit status of curl. If it's 0, the command was successful.
if [[ $? -eq 0 ]]; then
if [ "$(echo $husarnet_api_response | yq -r .result.is_ready)" != "true" ]; then
if [[ $i -eq 7 ]]; then
echo "Husarnet API is not ready."
echo "Error: Exiting..."
exit 1
else
echo "Husarnet API is not ready"
sleep 2
fi
else
echo "Husarnet API is ready!"
create_config_husarnet
export husarnet_ready=true
break
fi
else
if [[ $i -eq 5 ]]; then
echo "Can't reach Husarnet Daemon HTTP API after 5 retries"
echo "Error: Exiting..."
exit 1
else
echo "Failed to connect to Husarnet API endpoint. Retrying in 2 seconds..."
sleep 2
fi
fi
done
fi
if [[ $PARTICIPANT_LO_ENABLED == true ]]; then
echo ">> lo participant enabled"
yq -i '.participants += load("/participant.lo.yaml")' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
fi
if [[ $PARTICIPANT_SHM_ENABLED == true ]]; then
echo ">> SHM participant enabled"
yq -i '.participants += load("/participant.shm.yaml")' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
fi
if [[ $PARTICIPANT_LAN_ENABLED == true ]]; then
echo ">> LAN participant enabled"
yq -i '.participants += load("/participant.lan.yaml")' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
fi
if [[ $PARTICIPANT_ECHO_ENABLED == true ]]; then
echo ">> ECHO participant enabled"
yq -i '.participants += load("/participant.echo.yaml")' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
fi
if [[ ${#PARTICIPANT_IF_LIST[@]} -gt 0 ]]; then
echo ">> IF participants enabled"
yq -i '.participants += load("/participant.if.yaml")' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
for interface in "${PARTICIPANT_IF_LIST[@]}"; do
# Get the IP address associated with the network interface
export local_ip=$(ip addr show $interface | grep 'inet ' | awk '{print $2}' | cut -d/ -f1)
if [ ! -z "$local_ip" ]; then
echo "$interface: $local_ip"
yq -i '(.participants[] | select(.name == "IfParticipant").whitelist-interfaces) += strenv(local_ip)' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
else
echo "$interface: no IP address assigned"
fi
done
fi
if [ -n "${ROS_DOMAIN_ID}" ]; then
yq -i '(.participants[] | select (.domain).domain ) = env(ROS_DOMAIN_ID)' $CFG_PATH/DDS_ROUTER_CONFIGURATION_base.yaml
fi
rm -f $CFG_PATH/config.yaml.tmp
rm -f /tmp/loop_done_semaphore
# Start a config_daemon
rm -f $CFG_PATH/config_daemon_logs_pipe
mkfifo $CFG_PATH/config_daemon_logs_pipe
cat <$CFG_PATH/config_daemon_logs_pipe &
pkill -f config_daemon.sh
# Starting config_daemon.sh as the specified user and redirecting output to the pipe
nohup ./config_daemon.sh >$CFG_PATH/config_daemon_logs_pipe 2>&1 &
# wait for the semaphore indicating the loop has completed once
while [ ! -f /tmp/loop_done_semaphore ]; do
sleep 0.1 # short sleep to avoid hammering the filesystem
done
}
run_auto_config