-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathinstall.sh
executable file
·440 lines (387 loc) · 14.4 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
#!/usr/bin/env bash
#
# Authentication service installation script for Linux systems.
#
# Copyright 2024, Perforce Software Inc. All rights reserved.
#
INTERACTIVE=true
MONOCHROME=false
CREATE_USER=true
ALLOW_ROOT=false
HOMEDIR=/opt/perforce
UPGRADE_NODE=false
NODE_VERSION=20
INSTALL_SERVICE=true
# Print arguments to STDERR and exit.
function die() {
error "FATAL: $*" >&2
exit 1
}
# Begin printing text in green.
function highlight_on() {
$MONOCHROME || echo -n -e "\033[32m"
$MONOCHROME && echo -n '' || true
}
# Reset text color to default.
function highlight_off() {
$MONOCHROME || echo -n -e "\033[0m"
$MONOCHROME && echo -n '' || true
}
# Print the first argument in red text on STDERR.
function error() {
$MONOCHROME || echo -e "\033[31m$1\033[0m" >&2
$MONOCHROME && echo -e "$1" >&2 || true
}
function usage() {
cat <<EOS
Usage:
install.sh [OPTIONS]
Description:
Install the authentication service and its dependencies, as well as
create and start a systemd service unit to manage the service.
--no-create-user
Do _not_ create the perforce user and group that will own the
systemd service.
--no-systemd
Do _not_ install the systemd service unit.
--upgrade
Upgrade an existing package-based installation of Node.js with
the latest supported version.
--allow-root
Allow the root user to run the install script. This may leave
some files owned and writable only by the root user, which can
cause other problems.
-m
Monochrome; no colored text.
-n
Non-interactive mode; exits immediately if prompting is required.
-h / --help
Display this help message.
See the Helix Authentication Service Administrator Guide for additional
information pertaining to configuring and running the service.
EOS
}
function read_arguments() {
while [[ -n "$1" ]]; do
case "$1" in
-m)
MONOCHROME=true
shift
;;
--no-create-user)
CREATE_USER=false
shift
;;
--no-systemd)
INSTALL_SERVICE=false
shift
;;
--upgrade)
UPGRADE_NODE=true
shift
;;
--allow-root)
ALLOW_ROOT=true
shift
;;
-n)
INTERACTIVE=false
shift
;;
-h)
usage
exit 0
;;
--help)
usage
exit 0
;;
--)
shift
break
;;
*)
die "Unknown option: $1"
exit 1
;;
esac
done
}
# Determine the platform version and packaging system.
function detect_platform() {
#
# Based on the apparent OS release determine which packaging system to use
# and which version of Node.js can be installed. Older releases do not have
# support for the latest Node.js from the nodesource.com repository.
#
# Looking for /etc/os-release is assuming that systemd is installed, which
# should be a given for the platforms that HAS supports.
#
ID=$(awk -F= '/^ID=/ {print $2}' /etc/os-release | tr -d '"')
if [[ "$ID" == 'amzn' ]]; then
PLATFORM=redhat
VERSION_ID=$(awk -F= '/VERSION_ID/ {print $2}' /etc/os-release | tr -d '"')
if [[ "$VERSION_ID" == '2' ]]; then
die 'Cannot support this OS release any longer, lacks Node.js LTS support.'
fi
elif [[ "$ID" == 'centos' ]]; then
PLATFORM=redhat
VERSION_ID=$(awk -F= '/VERSION_ID/ {print $2}' /etc/os-release | tr -d '"')
if [[ "$VERSION_ID" == '7' ]]; then
die 'Cannot support this OS release any longer, lacks Node.js LTS support.'
fi
elif [[ "$ID" == 'rocky' ]]; then
# For now, all Rocky releases support Node.js LTS, otherwise examine the
# VERSION_ID value and compare to something like "8.5" to decide.
PLATFORM=redhat
elif [[ "$ID" == 'ubuntu' ]]; then
PLATFORM=debian
CODENAME=$(awk -F= '/VERSION_CODENAME/ {print $2}' /etc/os-release | tr -d '"')
if [[ "$CODENAME" == 'xenial' || "$CODENAME" == 'bionic' ]]; then
die 'Cannot support this OS release any longer, lacks Node.js LTS support.'
fi
fi
}
# Check that prerequisites are met before starting installation.
function ensure_readiness() {
# This prevents a particular kind of error caused by npm trying to reduce
# its privileges when running the pre/post install scripts of certain Node
# modules, and subsequently running into a file permissions error. If the
# files are owned by root and root runs this script, it _should_ work.
if [[ $EUID -eq 0 ]] && ! $ALLOW_ROOT; then
die 'This script must be run as a non-root user.'
fi
# Test file permissions to ensure dependencies can be installed.
mkdir -p node_modules > /dev/null 2>&1
if [ $? != 0 ]; then
die 'You do not have permission to write to this directory.'
fi
# Ensure this system is supported by the installation script.
detect_platform
if [ -z "$PLATFORM" ]; then
die "Could not determine OS distribution"
fi
}
# Show a message about the interactive configuration procedure.
function display_interactive() {
highlight_on
cat <<EOT
This script will install the requirements for the Authentication Service.
The operations involved are as follows:
* Install OS packages for build dependencies
* Download and install Node.js v${NODE_VERSION} (https://nodejs.org)
* Download and build the service dependencies
* Create and start the systemd service unit to manage the service
This script will only install software on this machine. After this script is
finished, you will need to:
1) Configure the service by editing the .env file in the base directory.
2) Restart the service by invoking the following command:
$ systemctl restart helix-auth
EOT
highlight_off
}
# Prompt user to proceed with or cancel the configuration.
function prompt_to_proceed() {
echo 'Do you wish to continue?'
select yn in 'Yes' 'No'; do
case $yn in
Yes) break;;
No) exit;;
esac
done
}
# If Node.js is installed, ensure that the version is supported.
function check_nodejs() {
if command -v node >/dev/null 2>&1 && ! node --version | grep -Eq '^v(18|20)\.'; then
# check if Node.js came from the package 'nodejs' package or not
UPGRADABLE=true
if [ $PLATFORM == "debian" ]; then
if ! apt-cache policy nodejs | grep -Eq 'Installed:.+nodesource*'; then
UPGRADABLE=false
fi
elif [ $PLATFORM == "redhat" ]; then
if ! rpm -q nodejs >/dev/null 2>&1; then
UPGRADABLE=false
fi
fi
if ! $UPGRADABLE; then
error 'Found a version of Node.js that cannot be upgraded automatically.'
error 'Please upgrade Node.js to v18 or v20 before proceeding.'
exit 1
fi
if $INTERACTIVE; then
echo ''
echo 'Found a version of Node.js that is not the required v18/v20.'
echo 'Do you wish to upgrade the Node.js installation?'
select yn in 'Yes' 'No'; do
case $yn in
Yes) break;;
No) exit;;
esac
done
elif ! $UPGRADE_NODE; then
die 'Node.js v18 or v20 is required, please upgrade.'
fi
# else the script will automatically install the required version
fi
}
# Install or upgrade Node.js using a script from nodesource.com
function install_nodejs() {
# Both an upgrade and a new installation work in the same manner.
if $UPGRADE_NODE || ! command -v node >/dev/null 2>&1; then
echo "Preparing to install OS packages and Node.js..."
if [ $PLATFORM == "debian" ]; then
# Because apt-get will happily fail miserably _and_ return an exit code of
# 0, we are forced to check for a functional network connection rather than
# relying on set -e to work effectively with the apt-get command.
echo 'Checking network connection...'
set +e # don't exit due to ping returning non-zero, we want that code
ping -c 3 ubuntu.com > /dev/null 2>&1
if [ $? != 0 ]; then
die 'Unable to reach ubuntu.com, please check your connection'
fi
set -e # now go back to exiting if a command returns non-zero
sudo apt-get -q update
sudo apt-get -q -y install build-essential curl git
# Run a shell script from the internet as root to get Node.js
# directly from the vendor. This includes npm as well.
curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | sudo -E bash -
sudo apt-get -q -y install nodejs
elif [ $PLATFORM == "redhat" ]; then
# In the upgrade scenario, need to remove the repository package first.
if [ -f /etc/yum.repos.d/nodesource-el7.repo ]; then
sudo rpm -e nodesource-release-el7
elif [ -f /etc/yum.repos.d/nodesource-el8.repo ]; then
sudo rpm -e nodesource-release-el8
elif [ -f /etc/yum.repos.d/nodesource-nodistro.repo ]; then
sudo rpm -e nodesource-release
fi
# Add --skip-broken for Oracle Linux and its redundant packages
sudo yum -q -y install --skip-broken curl gcc-c++ git make
# Run a shell script from the internet as root to get Node.js
# directly from the vendor. This includes npm as well.
curl -fsSL https://rpm.nodesource.com/setup_${NODE_VERSION}.x | sudo bash -
sudo yum install -y nodejs
fi
fi
# run npm once as the unprivileged user so it creates the ~/.config
# directory with the unprivileged user as the owner, rather than as root
# when we run the very first 'npm install' command later
npm version >/dev/null 2>&1
}
# Create the perforce user and group, if permitted, and as needed.
function create_user_group() {
# create perforce group as needed
if ! getent group perforce >/dev/null; then
sudo groupadd --system perforce
fi
# create perforce user as needed
if ! getent passwd perforce >/dev/null; then
sudo useradd --system --comment 'Perforce Admin' --shell /bin/bash \
--gid perforce --home-dir "$HOMEDIR" perforce
fi
# create home directory and set ownership as needed
if [ ! -d "$HOMEDIR" ]; then
sudo mkdir -p "$HOMEDIR"
sudo chown -R perforce:perforce "$HOMEDIR"
fi
# ensure perforce user can write to the installation path
sudo chown -R perforce:perforce "$INSTALLPREFIX"
if ! sudo su - perforce -c "ls ${INSTALLPREFIX}" >/dev/null 2>&1; then
error "\n\nUser perforce cannot access ${INSTALLPREFIX}, please fix permissions.\n"
echo -e "For example, invoke 'chmod 755 $(dirname ${INSTALLPREFIX})' as the root user.\n"
fi
}
# Create a .env file if neither it nor the config.toml exist.
function create_env_if_missing() {
# create an example .env file if it and config.toml are missing
if [ ! -f .env ] && [ ! -f config.toml ]; then
PRINT="print \"LOGGING=${INSTALLPREFIX}/logging.config.cjs\""
# inject LOGGING if not already set; strip comments and blank lines
awk "BEGIN {flg=0} /^$/{next} /^#/{next} /^LOGGING=/{flg=1; ${PRINT}; next} {print} END {if(flg==0) ${PRINT}}" ${INSTALLPREFIX}/example.env | sudo tee .env >/dev/null
sudo chown --reference=example.env .env
fi
}
# Create the systemd service unit, enable, and start.
function install_service_unit() {
sudo tee /etc/systemd/system/helix-auth.service >/dev/null <<__SERVICE_UNIT__
[Unit]
Description=Helix Authentication Service
After=network.target
[Service]
Type=simple
Restart=always
ExecStart=${INSTALLPREFIX}/bin/www.js
WorkingDirectory=${INSTALLPREFIX}
[Install]
WantedBy=multi-user.target
__SERVICE_UNIT__
if command -v systemctl >/dev/null 2>&1; then
sudo systemctl daemon-reload
sudo systemctl enable helix-auth.service
sudo systemctl start helix-auth.service
else
error 'The systemctl utility was not found in the PATH.'
error 'You will need to start the helix-auth.service like so:'
error ' $ sudo systemctl daemon-reload'
error ' $ sudo systemctl enable helix-auth.service'
error ' $ sudo systemctl start helix-auth.service'
fi
}
# Fetch and build the application dependencies.
function install_modules() {
if ! test -f package.json; then
die 'Missing package.json file for authentication service'
fi
echo "Building dependencies for auth service..."
if test -f package-lock.json; then
npm ci -q --omit=dev
else
npm i -q --omit=dev
fi
}
# Print a summary of what was done and any next steps.
function print_summary() {
highlight_on
cat <<EOT
===============================================================================
Automated install complete! Now a few final bits to do manually.
===============================================================================
The Helix Authentication Service is now running via systemd using the service
name 'helix-auth'. Use the command 'sudo systemctl status helix-auth' to get
the status of the service.
To configure the service, edit the .env file in the directory shown below, and
then restart the service: sudo systemctl restart helix-auth
${INSTALLPREFIX}
In particular, the settings to be changed are the OIDC and/or SAML settings
for your identity provider. The configure-auth-service.js script may be
helpful for this purpose.
node ${INSTALLPREFIX}/bin/configure-auth-service.js --help
For assistance, please contact support@perforce.com
EOT
highlight_off
}
function main() {
# move to the source directory before everything else
cd "$( cd "$(dirname "$0")" ; pwd -P )"
INSTALLPREFIX=$(pwd)
set -e
read_arguments "$@"
ensure_readiness
check_nodejs
if $INTERACTIVE; then
display_interactive
prompt_to_proceed
fi
install_nodejs
install_modules
if $CREATE_USER; then
create_user_group
fi
create_env_if_missing
if $INSTALL_SERVICE; then
install_service_unit
fi
print_summary
}
main "$@"