forked from rocket-pool/smartnode-install
-
Notifications
You must be signed in to change notification settings - Fork 0
/
install.sh
executable file
·444 lines (363 loc) · 20 KB
/
install.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
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
#!/bin/sh
##
# Rocket Pool service installation script
# Prints progress messages to stdout
# All command output is redirected to stderr
##
COLOR_RED='\033[0;31m'
COLOR_YELLOW='\033[33m'
COLOR_RESET='\033[0m'
# Print a failure message to stderr and exit
fail() {
MESSAGE=$1
>&2 echo -e "\n${COLOR_RED}**ERROR**\n$MESSAGE${COLOR_RESET}"
exit 1
}
# Get CPU architecture
UNAME_VAL=$(uname -m)
ARCH=""
case $UNAME_VAL in
x86_64) ARCH="amd64" ;;
aarch64) ARCH="arm64" ;;
arm64) ARCH="arm64" ;;
*) fail "CPU architecture not supported: $UNAME_VAL" ;;
esac
# Get the platform type
PLATFORM=$(uname -s)
if [ "$PLATFORM" = "Linux" ]; then
if command -v lsb_release &>/dev/null ; then
PLATFORM=$(lsb_release -si)
elif [ -f "/etc/centos-release" ]; then
PLATFORM="CentOS"
elif [ -f "/etc/fedora-release" ]; then
PLATFORM="Fedora"
fi
fi
##
# Config
##
# The total number of steps in the installation process
TOTAL_STEPS="9"
# The Rocket Pool user data path
RP_PATH="$HOME/.rocketpool"
# The default smart node package version to download
PACKAGE_VERSION="latest"
# The default network to run Rocket Pool on
NETWORK="mainnet"
##
# Utils
##
# Print progress
progress() {
STEP_NUMBER=$1
MESSAGE=$2
echo "Step $STEP_NUMBER of $TOTAL_STEPS: $MESSAGE"
}
# Docker installation steps
add_user_docker() {
$SUDO_CMD usermod -aG docker $USER || fail "Could not add user to docker group."
}
# Detect installed privilege escalation programs
get_escalation_cmd() {
if type sudo > /dev/null 2>&1; then
SUDO_CMD="sudo"
elif type doas > /dev/null 2>&1; then
echo "NOTE: sudo not found, using doas instead"
SUDO_CMD="doas"
else
fail "Please make sure a privilege escalation command such as \"sudo\" is installed and available before installing Rocket Pool."
fi
}
# Install
install() {
##
# Initialization
##
# Parse arguments
while getopts "dp:u:n:v:" FLAG; do
case "$FLAG" in
d) NO_DEPS=true ;;
p) RP_PATH="$OPTARG" ;;
u) DATA_PATH="$OPTARG" ;;
n) NETWORK="$OPTARG" ;;
v) PACKAGE_VERSION="$OPTARG" ;;
*) fail "Incorrect usage." ;;
esac
done
if [ -z "$DATA_PATH" ]; then
DATA_PATH="$RP_PATH/data"
fi
# Get package files URL
if [ "$PACKAGE_VERSION" = "latest" ]; then
PACKAGE_URL="https://github.com/rocket-pool/smartnode-install/releases/latest/download/rp-smartnode-install.tar.xz"
else
PACKAGE_URL="https://github.com/rocket-pool/smartnode-install/releases/download/$PACKAGE_VERSION/rp-smartnode-install.tar.xz"
fi
# Create temporary data folder; clean up on exit
TEMPDIR=$(mktemp -d 2>/dev/null) || fail "Could not create temporary data directory."
trap 'rm -rf "$TEMPDIR"' EXIT
# Get temporary data paths
PACKAGE_FILES_PATH="$TEMPDIR/install"
##
# Installation
##
# OS dependencies
if [ -z "$NO_DEPS" ]; then
>&2 get_escalation_cmd
case "$PLATFORM" in
# Ubuntu / Debian / Raspbian
Ubuntu|Debian|Raspbian)
# Get platform name
PLATFORM_NAME=$(echo "$PLATFORM" | tr '[:upper:]' '[:lower:]')
# Install OS dependencies
progress 1 "Installing OS dependencies..."
{ $SUDO_CMD apt-get -y update || fail "Could not update OS package definitions."; } >&2
{ $SUDO_CMD apt-get -y install apt-transport-https ca-certificates curl gnupg gnupg-agent lsb-release software-properties-common chrony || fail "Could not install OS packages."; } >&2
# Check for existing Docker installation
progress 2 "Checking if Docker is installed..."
dpkg-query -W -f='${Status}' docker-ce 2>&1 | grep -q -P '^install ok installed$' > /dev/null
if [ $? != "0" ]; then
echo "Installing Docker..."
if [ ! -f /etc/apt/sources.list.d/docker.list ]; then
# Install the Docker repo
{ $SUDO_CMD mkdir -p /etc/apt/keyrings || fail "Could not create APT keyrings directory."; } >&2
{ curl -fsSL "https://download.docker.com/linux/$PLATFORM_NAME/gpg" | $SUDO_CMD gpg --dearmor -o /etc/apt/keyrings/docker.gpg || fail "Could not add docker repository key."; } >&2
{ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$PLATFORM_NAME $(lsb_release -cs) stable" | $SUDO_CMD tee /etc/apt/sources.list.d/docker.list > /dev/null || fail "Could not add docker repository."; } >&2
fi
{ $SUDO_CMD apt-get -y update || fail "Could not update OS package definitions."; } >&2
{ $SUDO_CMD apt-get -y install docker-ce docker-ce-cli docker-compose-plugin containerd.io || fail "Could not install Docker packages."; } >&2
fi
# Check for existing docker-compose-plugin installation
progress 2 "Checking if docker-compose-plugin is installed..."
dpkg-query -W -f='${Status}' docker-compose-plugin 2>&1 | grep -q -P '^install ok installed$' > /dev/null
if [ $? != "0" ]; then
echo "Installing docker-compose-plugin..."
if [ ! -f /etc/apt/sources.list.d/docker.list ]; then
# Install the Docker repo, removing the legacy one if it exists
{ $SUDO_CMD add-apt-repository --remove "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/$PLATFORM_NAME $(lsb_release -cs) stable"; } 2>/dev/null
{ $SUDO_CMD mkdir -p /etc/apt/keyrings || fail "Could not create APT keyrings directory."; } >&2
{ curl -fsSL "https://download.docker.com/linux/$PLATFORM_NAME/gpg" | $SUDO_CMD gpg --dearmor -o /etc/apt/keyrings/docker.gpg || fail "Could not add docker repository key."; } >&2
{ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$PLATFORM_NAME $(lsb_release -cs) stable" | $SUDO_CMD tee /etc/apt/sources.list.d/docker.list > /dev/null || fail "Could not add Docker repository."; } >&2
fi
{ $SUDO_CMD apt-get -y update || fail "Could not update OS package definitions."; } >&2
{ $SUDO_CMD apt-get -y install docker-compose-plugin || fail "Could not install docker-compose-plugin."; } >&2
{ $SUDO_CMD systemctl restart docker || fail "Could not restart docker daemon."; } >&2
else
echo "Already installed."
fi
# Add user to docker group
progress 3 "Adding user to docker group..."
>&2 add_user_docker
;;
# Centos
CentOS)
# Install OS dependencies
progress 1 "Installing OS dependencies..."
{ $SUDO_CMD yum install -y yum-utils chrony || fail "Could not install OS packages."; } >&2
{ $SUDO_CMD systemctl start chronyd || fail "Could not start chrony daemon."; } >&2
# Install docker
progress 2 "Installing docker..."
{ $SUDO_CMD yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo || fail "Could not add docker repository."; } >&2
{ $SUDO_CMD yum install -y docker-ce docker-ce-cli docker-compose-plugin containerd.io || fail "Could not install docker packages."; } >&2
{ $SUDO_CMD systemctl start docker || fail "Could not start docker daemon."; } >&2
{ $SUDO_CMD systemctl enable docker || fail "Could not set docker daemon to auto-start on boot."; } >&2
# Check for existing docker-compose-plugin installation
progress 2 "Checking if docker-compose-plugin is installed..."
yum -q list installed docker-compose-plugin 2>/dev/null 1>/dev/null
if [ $? != "0" ]; then
echo "Installing docker-compose-plugin..."
{ $SUDO_CMD yum install -y docker-compose-plugin || fail "Could not install docker-compose-plugin."; } >&2
{ $SUDO_CMD systemctl restart docker || fail "Could not restart docker daemon."; } >&2
else
echo "Already installed."
fi
# Add user to docker group
progress 3 "Adding user to docker group..."
>&2 add_user_docker
;;
# Fedora
Fedora)
# Install OS dependencies
progress 1 "Installing OS dependencies..."
{ $SUDO_CMD dnf -y install dnf-plugins-core chrony || fail "Could not install OS packages."; } >&2
{ $SUDO_CMD systemctl start chronyd || fail "Could not start chrony daemon."; } >&2
# Install docker
progress 2 "Installing docker..."
{ $SUDO_CMD dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo || fail "Could not add docker repository."; } >&2
{ $SUDO_CMD dnf -y install docker-ce docker-ce-cli docker-compose-plugin containerd.io || fail "Could not install docker packages."; } >&2
{ $SUDO_CMD systemctl start docker || fail "Could not start docker daemon."; } >&2
{ $SUDO_CMD systemctl enable docker || fail "Could not set docker daemon to auto-start on boot."; } >&2
# Check for existing docker-compose-plugin installation
progress 2 "Checking if docker-compose-plugin is installed..."
dnf -q list installed docker-compose-plugin 2>/dev/null 1>/dev/null
if [ $? != "0" ]; then
echo "Installing docker-compose-plugin..."
{ $SUDO_CMD dnf install -y docker-compose-plugin || fail "Could not install docker-compose-plugin."; } >&2
{ $SUDO_CMD systemctl restart docker || fail "Could not restart docker daemon."; } >&2
else
echo "Already installed."
fi
# Add user to docker group
progress 3 "Adding user to docker group..."
>&2 add_user_docker
;;
# Unsupported OS
*)
RED='\033[0;31m'
echo ""
echo -e "${RED}**ERROR**"
echo "Automatic dependency installation for the $PLATFORM operating system is not supported."
echo "Please install docker and docker-compose-plugin manually, then try again with the '-d' flag to skip OS dependency installation."
echo "Be sure to add yourself to the docker group with '$SUDO_CMD usermod -aG docker $USER' after installing docker."
echo "Log out and back in, or restart your system after you run this command."
echo -e "${RESET}"
exit 1
;;
esac
else
echo "Skipping steps 1 - 2 (OS dependencies & docker)"
case "$PLATFORM" in
# Ubuntu / Debian / Raspbian
Ubuntu|Debian|Raspbian)
# Get platform name
PLATFORM_NAME=$(echo "$PLATFORM" | tr '[:upper:]' '[:lower:]')
# Check for existing docker-compose-plugin installation
progress 3 "Checking if docker-compose-plugin is installed..."
dpkg-query -W -f='${Status}' docker-compose-plugin 2>&1 | grep -q -P '^install ok installed$' > /dev/null
if [ $? != "0" ]; then
>&2 get_escalation_cmd
echo "Installing docker-compose-plugin..."
if [ ! -f /etc/apt/sources.list.d/docker.list ]; then
# Install the Docker repo, removing the legacy one if it exists
{ $SUDO_CMD add-apt-repository --remove "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/$PLATFORM_NAME $(lsb_release -cs) stable"; } 2>/dev/null
{ $SUDO_CMD mkdir -p /etc/apt/keyrings || fail "Could not create APT keyrings directory."; } >&2
{ curl -fsSL "https://download.docker.com/linux/$PLATFORM_NAME/gpg" | $SUDO_CMD gpg --dearmor -o /etc/apt/keyrings/docker.gpg || fail "Could not add docker repository key."; } >&2
{ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$PLATFORM_NAME $(lsb_release -cs) stable" | $SUDO_CMD tee /etc/apt/sources.list.d/docker.list > /dev/null || fail "Could not add Docker repository."; } >&2
fi
{ $SUDO_CMD apt-get -y update || fail "Could not update OS package definitions."; } >&2
{ $SUDO_CMD apt-get -y install docker-compose-plugin || fail "Could not install docker-compose-plugin."; } >&2
{ $SUDO_CMD systemctl restart docker || fail "Could not restart docker daemon."; } >&2
else
echo "Already installed."
fi
;;
# Centos
CentOS)
# Check for existing docker-compose-plugin installation
progress 3 "Checking if docker-compose-plugin is installed..."
yum -q list installed docker-compose-plugin 2>/dev/null 1>/dev/null
if [ $? != "0" ]; then
>&2 get_escalation_cmd
echo "Installing docker-compose-plugin..."
{ $SUDO_CMD yum install -y docker-compose-plugin || fail "Could not install docker-compose-plugin."; } >&2
{ $SUDO_CMD systemctl restart docker || fail "Could not restart docker daemon."; } >&2
else
echo "Already installed."
fi
;;
# Fedora
Fedora)
# Check for existing docker-compose-plugin installation
progress 3 "Checking if docker-compose-plugin is installed..."
dnf -q list installed docker-compose-plugin 2>/dev/null 1>/dev/null
if [ $? != "0" ]; then
>&2 get_escalation_cmd
echo "Installing docker-compose-plugin..."
{ $SUDO_CMD dnf install -y docker-compose-plugin || fail "Could not install docker-compose-plugin."; } >&2
{ $SUDO_CMD systemctl restart docker || fail "Could not restart docker daemon."; } >&2
else
echo "Already installed."
fi
;;
# Everything else
*)
# Check for existing docker-compose-plugin installation
progress 3 "Checking if docker-compose-plugin is installed..."
if docker compose 2>/dev/null 1>/dev/null ; then
echo "Already installed."
else
RED='\033[0;31m'
echo ""
echo -e "${RED}**ERROR**"
echo "The docker-compose-plugin package is not installed. Starting with v1.7.0, the Smartnode requires this package because the legacy docker-compose script is no longer supported."
echo "Since automatic dependency installation for the $PLATFORM operating system is not supported, you will need to install it manually."
echo "Please install docker-compose-plugin manually, then try running `rocketpool service install -d` again to finish updating."
echo -e "${RESET}"
exit 1
fi
;;
esac
fi
# Check for existing installation
progress 5 "Checking for existing installation..."
if [ -d $RP_PATH ]; then
# Check for legacy files - key on the old config.yml
if [ -f "$RP_PATH/config.yml" ]; then
progress 5 "Old installation detected, backing it up and migrating to new config system..."
OLD_CONFIG_BACKUP_PATH="$RP_PATH/old_config_backup"
{ mkdir -p $OLD_CONFIG_BACKUP_PATH || fail "Could not create old config backup folder."; } >&2
if [ -f "$RP_PATH/config.yml" ]; then
{ mv "$RP_PATH/config.yml" "$OLD_CONFIG_BACKUP_PATH" || fail "Could not move config.yml to backup folder."; } >&2
fi
if [ -f "$RP_PATH/settings.yml" ]; then
{ mv "$RP_PATH/settings.yml" "$OLD_CONFIG_BACKUP_PATH" || fail "Could not move settings.yml to backup folder."; } >&2
fi
if [ -f "$RP_PATH/docker-compose.yml" ]; then
{ mv "$RP_PATH/docker-compose.yml" "$OLD_CONFIG_BACKUP_PATH" || fail "Could not move docker-compose.yml to backup folder."; } >&2
fi
if [ -f "$RP_PATH/docker-compose-metrics.yml" ]; then
{ mv "$RP_PATH/docker-compose-metrics.yml" "$OLD_CONFIG_BACKUP_PATH" || fail "Could not move docker-compose-metrics.yml to backup folder."; } >&2
fi
if [ -f "$RP_PATH/docker-compose-fallback.yml" ]; then
{ mv "$RP_PATH/docker-compose-fallback.yml" "$OLD_CONFIG_BACKUP_PATH" || fail "Could not move docker-compose-fallback.yml to backup folder."; } >&2
fi
if [ -f "$RP_PATH/prometheus.tmpl" ]; then
{ mv "$RP_PATH/prometheus.tmpl" "$OLD_CONFIG_BACKUP_PATH" || fail "Could not move prometheus.tmpl to backup folder."; } >&2
fi
if [ -f "$RP_PATH/grafana-prometheus-datasource.yml" ]; then
{ mv "$RP_PATH/grafana-prometheus-datasource.yml" "$OLD_CONFIG_BACKUP_PATH" || fail "Could not move grafana-prometheus-datasource.yml to backup folder."; } >&2
fi
if [ -d "$RP_PATH/chains" ]; then
{ mv "$RP_PATH/chains" "$OLD_CONFIG_BACKUP_PATH" || fail "Could not move chains directory to backup folder."; } >&2
fi
fi
# Back up existing config file
if [ -f "$RP_PATH/user-settings.yml" ]; then
progress 5 "Backing up configuration settings to user-settings-backup.yml..."
{ cp "$RP_PATH/user-settings.yml" "$RP_PATH/user-settings-backup.yml" || fail "Could not backup configuration settings."; } >&2
fi
fi
# Create ~/.rocketpool dir & files
progress 6 "Creating Rocket Pool user data directory..."
{ mkdir -p "$DATA_PATH/validators" || fail "Could not create the Rocket Pool user data directory."; } >&2
{ mkdir -p "$RP_PATH/runtime" || fail "Could not create the Rocket Pool runtime directory."; } >&2
{ mkdir -p "$DATA_PATH/secrets" || fail "Could not create the Rocket Pool secrets directory."; } >&2
{ mkdir -p "$DATA_PATH/rewards-trees" || fail "Could not create the Rocket Pool rewards trees directory."; } >&2
{ mkdir -p "$RP_PATH/extra-scrape-jobs" || fail "Could not create the Prometheus extra scrape jobs directory."; } >&2
{ mkdir -p "$RP_PATH/alerting/rules" || fail "Could not create the alerting rules directory."; } >&2
# Download and extract package files
progress 7 "Downloading Rocket Pool package files..."
{ curl -L "$PACKAGE_URL" | tar -xJ -C "$TEMPDIR" || fail "Could not download and extract the Rocket Pool package files."; } >&2
{ test -d "$PACKAGE_FILES_PATH" || fail "Could not extract the Rocket Pool package files."; } >&2
# Copy package files
progress 8 "Copying package files to Rocket Pool user data directory..."
{ cp -r "$PACKAGE_FILES_PATH/addons" "$RP_PATH" || fail "Could not copy addons folder to the Rocket Pool user data directory."; } >&2
{ cp -r -n "$PACKAGE_FILES_PATH/override" "$RP_PATH" || rsync -r --ignore-existing "$PACKAGE_FILES_PATH/override" "$RP_PATH" || fail "Could not copy new override files to the Rocket Pool user data directory."; } >&2
{ cp -r "$PACKAGE_FILES_PATH/scripts" "$RP_PATH" || fail "Could not copy scripts folder to the Rocket Pool user data directory."; } >&2
{ cp -r "$PACKAGE_FILES_PATH/templates" "$RP_PATH" || fail "Could not copy templates folder to the Rocket Pool user data directory."; } >&2
{ cp -r "$PACKAGE_FILES_PATH/alerting" "$RP_PATH" || fail "Could not copy alerting folder to the Rocket Pool user data directory."; } >&2
{ cp "$PACKAGE_FILES_PATH/grafana-prometheus-datasource.yml" "$PACKAGE_FILES_PATH/prometheus.tmpl" "$RP_PATH" || fail "Could not copy base files to the Rocket Pool user data directory."; } >&2
{ find "$RP_PATH/scripts" -name "*.sh" -exec chmod +x {} \; 2>/dev/null || fail "Could not set executable permissions on package files."; } >&2
{ touch -a "$RP_PATH/.firstrun" || fail "Could not create the first-run flag file."; } >&2
# Clean up unnecessary files from old installations
progress 9 "Cleaning up obsolete files from previous installs..."
{ rm -rf "$DATA_PATH/fr-default" || echo "NOTE: Could not remove '$DATA_PATH/fr-default' which is no longer needed."; } >&2
GRAFFITI_OWNER=$(stat -c "%U" $RP_PATH/addons/gww/graffiti.txt)
if [ "$GRAFFITI_OWNER" = "$USER" ]; then
{ rm -f "$RP_PATH/addons/gww/graffiti.txt" || echo -e "${COLOR_YELLOW}WARNING: Could not remove '$RP_PATH/addons/gww/graffiti.txt' which was used by the Graffiti Wall Writer addon. You will need to remove this file manually if you intend to use the Graffiti Wall Writer.${COLOR_RESET}"; } >&2
fi
}
# Remove deprecated version tags
find $RP_PATH/override/ -name "*.yml" -exec sed -i '/^version: "3\.7"$/d' {} \;
find $RP_PATH/templates/ -name "*.tmpl" -exec sed -i '/^version: "3\.7"$/d' {} \;
install "$@"