/
start-blueos-core
executable file
·164 lines (141 loc) · 7.54 KB
/
start-blueos-core
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
#!/usr/bin/env bash
# Immediately exit on errors
set -e
BLUEOS_PATH=/home/pi
SERVICES_PATH=$BLUEOS_PATH/services
TOOLS_PATH=$BLUEOS_PATH/tools
# MAVLink configuration
MAV_SYSTEM_ID=1
## We use the last ID for the onboard computer component reserved address for our usage
MAV_COMPONENT_ID_ONBOARD_COMPUTER4=194
# Enable Rust backtrace for all programs
RUST_BACKTRACE=1
# Set BlueOS log folder
BLUEOS_LOG_FOLDER_PATH="/var/logs/blueos"
# The system may start with full disk, in this case resulting in an unstable behavior.
# As an attempt to recover the system, lets delete the log files before current boot
AVAILABLE_SPACE_MB=$(($(stat -f / --format="%a*%S/1024**2")))
CRITICAL_SPACE_LIMIT_MB=100
echo "Available disk space: ${AVAILABLE_SPACE_MB}MB"
(( AVAILABLE_SPACE_MB < CRITICAL_SPACE_LIMIT_MB )) && (
LOG_FOLDER_SIZE=$(($(du -sm ${BLUEOS_LOG_FOLDER_PATH} | awk '{print $1}')))
echo "Not enough free space for the system to run, limit is: ${CRITICAL_SPACE_LIMIT_MB}MB"
echo "Going to delete the logs folder as an attempt to recover: ${LOG_FOLDER_SIZE}MB"
rm -rf "$BLUEOS_LOG_FOLDER_PATH/*"
echo "Done!"
)
TOTAL_RAM_MB=$(free -m | awk '/Mem:/ {print $2}')
echo "Total RAM size: ${TOTAL_RAM_MB} MB"
# Update docker binds, if we need to restart, exit!
blueos_startup_update
# Set permission of docker unix socket file to be accessible by nginx
if [ -e "/var/run/docker.sock" ]; then
chmod 777 /var/run/docker.sock
else
echo "Error: Docker socket file does not exist!"
fi
# Generate hardware identification uuid
if [ -e "/etc/blueos" ]; then
machineid-cli --key blueos --parts cpu-cores cpuid mac-address > /etc/blueos/hardware-uuid
else
echo "Error: blueos static system configuration folder does not exist!"
fi
# This is a workaround to make the container's `resolv.conf` synchronized with the host's
# `resolv.conf`. To do that, we disallow docker from managing the container's DNS nameservers
# by unmounting the container's `/etc/resolv.conf`, and soft linking it to the binded host's
# `/etc/resolv.conf`.
# So for this to work, the container's `/etc/resolv.conf.host` file should be binded (read-only) to
# the host's `/etc/resolv.conf`, for our system, it's configured in `bootstrap/startup.json.default`,
# and a patch is added in `core/tools/blueos_startup_update` so systems with older bootstrap
# versions can also work with it.
# One detail is that because docker uses `mount` to bind the host's file to the container's file,
# if the file-descriptor of the file changes, the bind will be lost. To prevent this, the file being
# binded must be a hard link to the actual `/etc/resolv.conf`, and that hard link file is the one
# being binded. This hard link is being done in `core/tools/blueos_startup_update` as
# `/etc/resolv.conf.host`.
# To briefly understand why it is necessary, when the docker starts a container, it generates
# the container `/etc/resolv.conf` based on the host's one, or some docker configuration, however,
# during the container's lifetime, if the host's DNS configuration changes, the container's DNS
# doesn't follow it, making the container (possibly) unable to resolve DNSs correctly, failing
# the BlueOS Helper's internet connection check. By syncing the container's resolv.conf with the
# host's one, we make sure the container's DNS configuration follows the host's changes, thus,
# ensuring the container is able to resolve DNSs correctly.
HOST_RESOLV_CONF=/etc/resolv.conf.host
if [ -f "$HOST_RESOLV_CONF" ]; then
echo "Using host's resolv.conf instead of the one from the docker"
umount /etc/resolv.conf
rm /etc/resolv.conf
ln -s $HOST_RESOLV_CONF /etc/resolv.conf
else
echo "Waring: Using dockers's resolv.conf, this may cause DNS issues if the host's network configuration changes."
fi
# These services have priority because they do the fundamental for the vehicle to work,
# and by initializing them first we reduce the time users have to wait to control the vehicle.
# From tests with QGC and Pi3, the reboot time was ~1min42s when not using this strategy,
# and ~1min30s using this strategy.
# From that 1min30s, the startup time is about ~25s, and originally, ~37s, meaning that the
# remaining (~65 seconds) is the docker shutting down, and the Linux booting up.
PRIORITY_SERVICES=(
'autopilot',0,"nice --19 $SERVICES_PATH/ardupilot_manager/main.py"
'cable_guy',0,"$SERVICES_PATH/cable_guy/main.py"
'video',0,"nice --19 mavlink-camera-manager --default-settings BlueROVUDP --mavlink tcpout:127.0.0.1:5777 --mavlink-system-id $MAV_SYSTEM_ID --gst-feature-rank omxh264enc=0,v4l2h264enc=250,x264enc=260 --log-path /var/logs/blueos/services/mavlink-camera-manager --verbose"
'mavlink2rest',0,"mavlink2rest --connect=udpin:127.0.0.1:14000 --server 0.0.0.0:6040 --system-id $MAV_SYSTEM_ID --component-id $MAV_COMPONENT_ID_ONBOARD_COMPUTER4"
)
SERVICES=(
# This services are not prioritized because they are not fundamental for the vehicle to work
'kraken',0,"nice -19 $SERVICES_PATH/kraken/main.py"
'wifi',0,"nice -19 $SERVICES_PATH/wifi/main.py --socket wlan0"
# This services are not as important as the others
'beacon',250,"$SERVICES_PATH/beacon/main.py"
'bridget',250,"nice -19 $SERVICES_PATH/bridget/main.py"
'commander',250,"$SERVICES_PATH/commander/main.py"
'nmea_injector',250,"nice -19 $SERVICES_PATH/nmea_injector/nmea_injector/main.py"
'helper',250,"$SERVICES_PATH/helper/main.py"
'iperf3',250," iperf3 --server --port 5201"
'linux2rest',250,"linux2rest"
'filebrowser',250,"nice -19 filebrowser --database /etc/filebrowser/filebrowser.db --baseurl /file-browser"
'versionchooser',250,"$SERVICES_PATH/versionchooser/main.py"
'pardal',250,"nice -19 $SERVICES_PATH/pardal/main.py"
'ping',250,"nice -19 $SERVICES_PATH/ping/main.py"
'user_terminal',0,"cat /etc/motd"
'ttyd',250,'nice -19 ttyd -p 8088 sh -c "/usr/bin/tmux attach -t user_terminal || /usr/bin/tmux new -s user_terminal"'
'nginx',250,"nice -18 nginx -g \"daemon off;\" -c $TOOLS_PATH/nginx/nginx.conf"
'log_zipper',250,"nice -20 $SERVICES_PATH/log_zipper/main.py '/shortcuts/system_logs/\\\\*\\\\*/\\\\*.log' --max-age-minutes 60"
'bag_of_holding',250,"$SERVICES_PATH/bag_of_holding/main.py"
)
tmux -f /etc/tmux.conf start-server
function create_service {
tmux new -d -s "$1" || true
SESSION_NAME="$1:0"
local command="$2" # Store the command as a string
local memory_limit_mb=$3
if [ -n "${BLUEOS_DISABLE_MEMORY_LIMIT}" ]; then
memory_limit_mb=$TOTAL_RAM_MB
fi
# Check if the service is disabled
if [[ $BLUEOS_DISABLE_SERVICES == *"$1"* ]]; then
echo "Service: $1 is disabled"
tmux send-keys -t $SESSION_NAME "echo 'Service $1 is disabled'; sleep infinity" C-m
return
fi
echo "Service: $NAME: $EXECUTABLE with memory limit: $memory_limit_mb MB"
# Set all necessary environment variables for the new tmux session
for NAME in $(compgen -v | grep -e MAV_ -e BLUEOS_); do
VALUE=${!NAME}
tmux setenv -t $SESSION_NAME -g $NAME $VALUE
done
# Use run_service to start the service with the memory limit
tmux send-keys -t $SESSION_NAME "run-service '$command' $memory_limit_mb" C-m
}
echo "Starting high priority services.."
for TUPLE in "${PRIORITY_SERVICES[@]}"; do
IFS=',' read -r NAME MEMORY_LIMIT_MB EXECUTABLE <<< "$TUPLE"
create_service "$NAME" "$EXECUTABLE" "$MEMORY_LIMIT_MB"
done
sleep 5
echo "Starting other services.."
for TUPLE in "${SERVICES[@]}"; do
IFS=',' read -r NAME MEMORY_LIMIT_MB EXECUTABLE <<< "$TUPLE"
create_service "$NAME" "$EXECUTABLE" "$MEMORY_LIMIT_MB"
done
echo "BlueOS running!"